EF 4.1代码优先-当使用新的上下文/over WCF时,更改FK值不更新



我在WCF上使用EF Code First。所以当我保存一个实体时它会使用一个新的上下文。

如果我检索一个实体,然后更新它,使它引用一个不同的实体,我发现它保存了原始的外键值。

例如,我检索Company类,其中国家是UK。然后我将其更改为USA并将其传递回服务。当我查看表格时,FK仍然设置为UK。

如何更新外键?

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.Entity.ModelConfiguration;
using System.ComponentModel.DataAnnotations;
using System.Data.Entity;
using System.Data;
namespace CodeFirstExistingDatabase
{
    class Program
    {
        private const string ConnectionString = @"Server=.sql2005;Database=CodeFirst2;integrated security=SSPI;";
        static void Main(string[] args)
        {
            // Firstly, create a new country record.
            Country country = new Country();
            country.Code = "UK";
            country.Name = "United Kingdom";
            // Create aother new country record.
            Country country2 = new Country();
            country2.Code = "USA";
            country2.Name = "US of A";
            // Now create an instance of the context.
            MyContext myContext = new MyContext(ConnectionString);
            myContext.Entry(country).State = EntityState.Added;
            myContext.Entry(country2).State = EntityState.Added;
            myContext.SaveChanges();
            Console.WriteLine("Saved Countries");
            // Now insert a Company record
            Company company = new Company();
            company.CompanyName = "AccessUK";
            company.HomeCountry = myContext.Countries.First(e => e.Code == "UK");
            myContext.Companies.Add(company);
            myContext.SaveChanges();
            Console.WriteLine("Saved Company");
            Company savedCompany = myContext.Companies.First(e => e.CompanyName == "AccessUK");
            Country usCountry = myContext.Countries.First(e => e.Code == "USA");
            savedCompany.HomeCountry = usCountry;
            // Create another context for the save (as if we're passing the entity back over WCF and thus
            // creating a new context in the service)
            MyContext myContext2 = new MyContext(ConnectionString);
            myContext2.Entry(savedCompany).State = EntityState.Modified;
            myContext2.Entry(savedCompany.HomeCountry).State = EntityState.Modified;
            myContext2.SaveChanges();
            // When I check the company table, it has the foreign key of the UK Country.  It should have 
            // that of USA.
            Console.WriteLine("Finished");
            Console.ReadLine();
        }
    }
        public class MyContext
            : DbContext
        {
            public DbSet<Company> Companies { get; set; }
            public DbSet<Country> Countries { get; set; }
            public MyContext(string connectionString)
                : base(connectionString)
            {
            }
            protected override void OnModelCreating(DbModelBuilder modelBuilder)
            {
                modelBuilder.Configurations.Add(new CountryConfiguration());
                modelBuilder.Configurations.Add(new CompanyConfiguration());
                base.OnModelCreating(modelBuilder);
            }
        }
    public class CompanyConfiguration
        : EntityTypeConfiguration<Company>
    {
        public CompanyConfiguration()
            : base()
        {
            HasKey(p => p.Id);
            Property(p => p.Id)
                .HasColumnName("Id")
                .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity)
                .IsRequired();
            Property(p => p.CompanyName)
                .HasColumnName("Name")
                .IsRequired();
            HasRequired(x => x.HomeCountry).WithMany()
                .Map(x => x.MapKey("HomeCountryId"));
            ToTable("Companies");
        }
    }
    public class CountryConfiguration
        : EntityTypeConfiguration<Country>
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="CountryConfiguration"/> class.
        /// </summary>
        public CountryConfiguration()
            : base()
        {
            HasKey(p => p.Id);
            Property(p => p.Id)
                .HasColumnName("Id")
                .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity)
                .IsRequired();
            Property(p => p.Code)
                .HasColumnName("Code")
                .IsRequired();
            Property(p => p.Name)
                .HasColumnName("Name")
                .IsRequired();
            ToTable("Countries");
        }
    }
    public class Company
    {
        public int Id { get; set; }
        public string CompanyName { get; set; }
        public Country HomeCountry { get; set; }
    }
    public class Country
    {
        public int Id { get; set; }
        public string Code { get; set; }
        public string Name { get; set; }
    }
}
许多谢谢,

保罗。

这是众所周知的分离实体和独立关联的问题。问题是,将实体设置为modified并不会将关系设置为modified。关于所有相关问题的详细说明在这里。答案与EFv4和ObjectContext API有关,但EFv4.1只是一个包装器,所以意义是一样的。

这个问题的根源是,如果你使用分离实体,你必须说EF关系已经改变。EF不会为您做任何假设。DbContext API的问题甚至更糟,因为DbContext API不提供方法来改变独立关联的状态,所以你必须返回到ObjectContext API并使用ObjectStateManager.ChangeRelationshipState

还有其他方法如何处理它,如果你不使用远程调用作为WCF -它只是命令的顺序,你必须做这个工作,但当使用WCF你不能附加实体之前,你设置的关系等。理论上可以,但是这会彻底改变你的服务契约和消息编排。

因此,在这种情况下,通常最简单的解决方案是使用外键关联而不是独立关联。外键关联不像独立关联那样被跟踪为具有状态的单独对象,因此将实体的状态更改为modified就可以了。

public class Company
{
    public int Id { get; set; }
    public string CompanyName { get; set; }
    public int HomeCountryId { get; set; }
    public Country HomeCountry { get; set; }
}

HasRequired(x => x.HomeCountry)
    .WithMany()
    .HasForeignKey(x => x.HomeCountryId);

任何其他解决方案都是关于首先从DB加载旧对象并将更改合并到附加对象中-这就是我一直在做的事情,一旦您开始使用多对多关系或在一对多关系中删除,您将不得不这样做。

相关内容

  • 没有找到相关文章

最新更新