我一直在尝试使用EF 4.1代码优先的方式来映射一对多,单向的关系,例如,用户有地址但地址对用户一无所知。使用ForeignKey属性或流利的api(显示在包含的代码中),这很简单。如何在EF 4.1代码中首次创建新对象时防止引用对象的版本列更新?
在两个映射的类上添加具有Timestamp属性的Version(byte [])列时,问题就出现了。如果我们现在创建一个具有对现有(在数据库)地址中的引用并将其添加到上下文的用户实例,则在调用SaveChanges时,数据库概要分析器将显示两个数据库查询,一个是用户插入,另一个是用户插入,另一个是更新地址表以更改版本。不是我想要的。如果我在我的域中没有建立任何关系,那么我也不希望任何版本更改。如果我更改地址实例,我只想在地址上更改版本。
我怀疑因为映射使用HasMany()
,因此在内部EF DbContext认为有一个需要满足的集合,并且在集合发生更改(通过添加新用户)时,它会自动更新Address的版本。所有这些尽管事实上地址没有收集财产类型ICollection<User>
。
所以对我的问题。在添加新用户时,我需要为关系维护类结构的映射,因为它们没有更改地址版本?
编辑: 我发现,我可以防止地址版本更新的唯一方法是减少映射到一个HasRequired(a => a.Address)只有和不再有AddressId外键在User类上。看起来如果外键“属性”是在用户显式映射或约定映射将确保地址的版本更新。
我宁愿将一些扩展应用于HasRequired来告诉上下文如何处理关系,而不是完全删除外键属性。
这是我用来证明该问题的代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel.DataAnnotations;
using System.Data.Entity;
namespace DbTest
{
class Program
{
static void Main(string[] args)
{
Address address = null;
// Make sure we have one address to test with
using (var context = new DemoContext())
{
address = context.Addresses.FirstOrDefault();
if (address == null)
{
address = new Address { Street = "My Street" };
context.Addresses.Add(address);
context.SaveChanges();
}
}
byte[] version = address.Version;
using (var context = new DemoContext())
{
// Uncomment to test attaching
// context.Addresses.Attach(address);
address = context.Addresses.FirstOrDefault();
var user = new User { Name = "Mark", Address = address };
context.Users.Add(user);
context.SaveChanges(); // Results in new user inserted and a version update to the Address referenced object
}
using (var context = new DemoContext())
{
var address2 = context.Addresses.FirstOrDefault();
Console.WriteLine("Versions: {0}, {1}", BitConverter.ToString(version), BitConverter.ToString(address2.Version));
}
Console.ReadLine();
}
}
public class User
{
[Key]
public int UserId { get; set; }
public string Name { get; set; }
public int AddressId { get; set; }
// [ForeignKey("AddressId")]
public Address Address { get; set; }
[Timestamp]
public byte[] Version { get; set; }
}
public class Address
{
[Key]
public int AddressId { get; set; }
public string Street { get; set; }
[Timestamp]
public byte[] Version { get; set; }
}
public class DemoContext : DbContext
{
public DbSet<User> Users { get; set; }
public DbSet<Address> Addresses { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<User>()
.HasRequired(a => a.Address)
.WithMany()
.HasForeignKey(u => u.AddressId);
}
}
}
虽然它的作品只有当地址,如果不是已经在上下文中才有用。如果它在上下文中,版本将被更新。 – Mark 2011-12-22 00:37:07
...因此请检查它并首先从上下文中分配地址。 – nathanchere 2015-04-08 13:44:45