我在 WCF 上使用 EF Code First。所以当我保存一个实体时,它使用了一个新的上下文。
如果我检索一个实体,然后更新它以引用不同的实体,我发现它与原始外键值一起保存。
例如,我检索一个 Company 类,其中国家是英国。然后我将其更改为 USA 并将其传递回服务。当我检查表时,FK 仍然设置为英国的。
我怎样才能让它更新外键?
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; }
}
}
非常感谢,
保罗。
最佳答案
这是分离实体和独立关联的众所周知的问题。问题是将实体设置为已修改并没有将关系设置为已修改。所有相关问题的详细说明 is here .答案与 EFv4 和 ObjectContext API 有关,但 EFv4.1 只是它的包装器,因此含义相同。
这个问题的根源是,如果你使用分离的实体,你必须说 EF 关系已经改变。 EF 不会为您做任何假设。 DbContext API 的问题更糟,因为 DbContext API doesn't offer methods to change state of independent association所以你必须恢复到 ObjectContext API 并使用 ObjectStateManager.ChangeRelationshipState
.
如果您不将远程调用用作 WCF,还有其他方法可以处理它 - 这只是您必须执行的命令顺序才能使其工作,但是在使用 WCF 时,您无法在设置关系等之前附加实体. 好吧,理论上你可以,但它会彻底改变你的服务契约(Contract)和消息编排。
所以通常在这种情况下最简单的解决方案是使用 foreign key association instead of independent association .外键关联不会作为具有状态的单独对象(作为独立关联)进行跟踪,因此将实体的状态更改为已修改将起作用。
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 加载旧对象并将更改合并到附加对象中 - 这就是我一直在做的事情,一旦开始处理多对多关系或删除一个,就必须这样做- 对多关系。
关于wcf - EF 4.1 Code First - 使用新上下文/WCF 时未更新 FK 值的更改,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5729031/