开发者

Entity Framework 4.1 Problems Updating Foreign Key Properties

开发者 https://www.devze.com 2023-03-30 04:54 出处:网络
I am working on an application using Entity Framework 4.1 with DbContext API, in a disconnected environment. I have two basic entities, Person and Degree. Degree has a non-mandatory one-to-many relati

I am working on an application using Entity Framework 4.1 with DbContext API, in a disconnected environment. I have two basic entities, Person and Degree. Degree has a non-mandatory one-to-many relationship to Person.

The issue is occurring when I update the DegreeId property on the Person entity to a different value. When I save the changes, EF generates an Update statement on the actual Degree table. This in turn causes a concurrency error violation when two or more users are using the application. I was able to find the issue while using SQL Profiler. I’ve tried several configuration variations using the Fluent API, but nothing seems to suppress the additional Update statement on the Degree table.

Here are my entities:

public partial class Person
    {
        public int PersonId { get; set; }
        public string FirstName { get; set; }
        public string MiddleName { get; set; }
        public string LastName { get; set; }
        public Nullable<int> DegreeId { get; set; }

        public Degree Degree { get; set; }
    }

public partial class Degree 
    {
        public int DegreeId { get; set; }
        public string Name { get; set; }
    }

In my Repository class, I am loading the Person object graph as such:

public override Person GetById(int id)
   {
         return DataContext.People
                    .Include(d => d.Degree)
                    .FirstOrDefault(x => x.PersonId == id);
   }

In my Service layer, I am getting a person record, and then updating the DegreeId property to a specific value. Note: UnitOfWork.Commit method exposes SaveChanges on DbContext.

using (var unitOfWork = IoC.Resolve<IUnitOfWork>())
  {
        var personRepository = new PersonRepository(unitOfWork);
        var person = personRepository.GetById(240);
        person.DegreeId = 1;
        personRepository.Update(person);
        unitOfWork.Commit();
  }

My repository update method attaches the person entity and marks the entity state as modified:

var state = DataContext.Entry(entity).State;
dbSet.Attach(entity);
DataContext.Entry(entity).State = EntityState.Modified; 

Here is the SQL statement found in the Profiler session:

exec sp_executesql N'declare @p int
update [Client].[Degree]
set @p = 0
where (([DegreeId] = @0) and ([RowVersion] = @1))
select [RowVersion]
from [Client].[Degree]
where @@ROWCOUNT > 0 and [DegreeId] = @0',N'@0 int,
@1 binary(8)',@0=1,@1=0x0000000000004469

Does anyone know how to stop EF from sending this update statement to SQL Ser开发者_Python百科ver? Is there something apparent in my entity configuration that causes EF to assume the Degree is also affected?

Thank you.


I was able to find the cause of this issue and prevent it from occurring, but I cannot really explain why it was occurring.

My tables include a TimeStamp column and a corresponding property in the base class for my entities. I did not show the base class in my original question because it only includes the RowVersion and other audit properties, which I assumed were irrelevant. One would think I would've learned by know not assume anything about Entity Framework.

Here is my base class definition for the Degree entity:

public abstract class EntityBase : ValidableObject, IEntityBase
{
    public virtual byte[] RowVersion { get; protected set; }
    public virtual DateTime? CreateDate { get; set; }
    public virtual string CreateUser { get; set; }
    public virtual DateTime? ModifyDate { get; set; }
    public virtual string ModifyUser { get; set; }
}

Here is my context model configuration for the Degree entity:

internal class DegreeConfiguration : EntityTypeConfiguration<Degree>
    {
        internal DegreeConfiguration()
            : base()
        {
            ToTable("Degree", "dbo");
            Property(x => x.RowVersion).IsRowVersion();
        }
    }

Because of my application requirements, I must load the Person entity using the Include method to eagerly load the Degree entity so the object graph is fully populated when the consumer requests the entity.

return ctx.People.Include(p => p.Degree).Where(x => x.PersonId == id).First();

When the DegreeId property of the Person object is modified and attached to the Context, the following Update statement is generated upon calling SaveChanges():

exec sp_executesql N'declare @p int
update [dbo].[Degree]
set @p = 0
where (([DegreeId] = @0) and ([RowVersion] = @1))
select [RowVersion]
from [dbo].[Degree]
where @@ROWCOUNT > 0 and [DegreeId] = @0',N'@0 int,
@1 binary(8)',@0=2,@1=0x00000000000007DF

This is occurring even though I am not knowingly updating the Degree entity and causes havoc when two or more users using the application simultaneously.

To suppress the Update statement from being generated on the Degree navigation property, I commented out the concurrency check on the model configuration as such:

internal class DegreeConfiguration : EntityTypeConfiguration<Degree>
    {
        internal DegreeConfiguration()
            : base()
        {
            ToTable("Degree", "dbo");
            //Property(x => x.RowVersion).IsRowVersion();
        }
    }

Upon re-executing the process, EF no longer generates the problematic Update statement.

I've done a considerable number of searches both on MS site for EF 4.1, as well as general Google searches. I cannot come up with any concrete explanations.

Thank you.

0

精彩评论

暂无评论...
验证码 换一张
取 消