实体框架,代码优先,更新与独立协会的"一对多"关系

Mar*_*tin 13 entity-framework associations code-first dbcontext

找到下面描述的场景的解决方案花了我太长时间.看似简单的事情应该被证明是相当困难的.问题是:

使用实体框架4.1(代码优先方法)和"独立关联"如何在"分离"场景(在我的案例中为Asp.Net)中为现有的"多对一"关系分配不同的结尾.

该模型:

我意识到使用ForeignKey关系而不是独立关联可能是一个选项,但我喜欢在我的Pocos中没有ForeignKey实现.

客户有一个或多个目标:

    public class Customer:Person
{
    public string Number { get; set; }
    public string NameContactPerson { get; set; }
    private ICollection<Target> _targets;

    // Independent Association
    public virtual ICollection<Target> Targets
    {
        get { return _targets ?? (_targets = new Collection<Target>()); }
        set { _targets = value; }
    }
}
Run Code Online (Sandbox Code Playgroud)

目标有一个客户:

    public class Target:EntityBase
{
    public string Name { get; set; }
    public string Description { get; set; }
    public string Note { get; set; }
    public virtual Address Address { get; set; }
    public virtual Customer Customer { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

客户派生自Person类:

    public class Person:EntityBase
{        
    public string Salutation { get; set; }
    public string Title { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set  ; }        
    public string Telephone1 { get; set; }
    public string Telephone2 { get; set; }
    public string Email { get; set; }        

    public virtual Address Address { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

EntityBase类提供了一些常见属性:

    public abstract class EntityBase : INotifyPropertyChanged
{
    public EntityBase()
    {
        CreateDate = DateTime.Now;
        ChangeDate = CreateDate;
        CreateUser = HttpContext.Current.User.Identity.Name;
        ChangeUser = CreateUser;
        PropertyChanged += EntityBase_PropertyChanged;
    }

    public void EntityBase_PropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        if (Id != new Guid())
        {
            ChangeDate = DateTime.Now;
            ChangeUser = HttpContext.Current.User.Identity.Name;
        }
    }

    protected virtual void OnPropertyChanged(PropertyChangedEventArgs e)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null) handler(this, e);
    }

    public event PropertyChangedEventHandler PropertyChanged;

    public Guid Id { get; set; }
    public DateTime CreateDate { get; set; }
    public DateTime? ChangeDate { get; set; }
    public string CreateUser { get; set; }
    public string ChangeUser { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

上下文:

    public class TgrDbContext : DbContext
{
    public DbSet<Person> Persons { get; set; }
    public DbSet<Address> Addresses { get; set; }
    public DbSet<Customer> Customers { get; set; }
    public DbSet<Target> Targets { get; set; }
    public DbSet<ReportRequest> ReportRequests { get; set; }

    // If OnModelCreating becomes to big, use "Model Configuration Classes"
    //(derived from EntityTypeConfiguration) instead
    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Person>().HasOptional(e => e.Address);            
        modelBuilder.Entity<Customer>().HasMany(c => c.Targets).WithRequired(t => t.Customer);            
    }

    public static ObjectContext TgrObjectContext(TgrDbContext tgrDbContext)
    {           
        return ((IObjectContextAdapter)tgrDbContext).ObjectContext;
    }
}
Run Code Online (Sandbox Code Playgroud)

Lad*_*nka 5

我等待@Martin的答案,因为有更多解决方案可以解决这个问题.这是另一个(至少它与ObjectContext API一起使用,因此它也应该与DbContext API一起使用):

// Existing customer
var customer = new Customer() { Id = customerId };
// Another existing customer
var customer2 = new Customer() { Id = customerId2 };

var target = new Target { ID = oldTargetId };
// Make connection between target and old customer
target.Customer = customer;

// Attach target with old customer
context.Targets.Attach(target);
// Attach second customer
context.Customers.Attach(customer2);
// Set customer to a new value on attached object (it will delete old relation and add new one)
target.Customer = customer2;

// Change target's state to Modified
context.Entry(target).State = EntityState.Modified;
context.SaveChanges();
Run Code Online (Sandbox Code Playgroud)

这里的问题是EF内部的状态模型和状态验证.具有强制关系的未更改或已修改状态的实体(在多方面)在没有其他处于已删除状态时不能在添加状态中具有独立关联.根本不允许修改关联状态.