3

我正在针对 SQL Server 2012 数据库使用实体框架(版本 4.3.1)POCO,并且我有这个数据模式......

Table2
======    
Table2Id : int : Identity (1,1) Primary Key not null
Name : nvarchar(10) not null

Table1
======    
Table1Id : int : Identity (1,1) Primary Key not null
Name : nvarchar(10) not null
Table2Id : int not null (foreign key to Table2)

Root
====
RootId : int : Identity (1,1) Primary Key not null
Table1Id : int not null (foreign key to Table1)
Table2Id : int not null (foreign key to Table2)

除了现在有趣的是,我不想在我的 Root 对象上为 Table2 设置一个属性,而是希望从 Table1 的相关 Table2 中填充该 ID 。

为了解释我的意思,这里是我的对象和上下文:

public class Root
{
    public int RootId { get; set; }
    public Table1 Table1 { get; set; }
}

public class Table1
{
    public int Table1Id { get; set; }
    public string Name { get; set; }
    public Table2 Table2 { get; set; }
    public virtual ICollection<Root> Roots { get; set; }
}

public class Table2
{
    public int Table2Id { get; set; }
    public string Name { get; set; }
    public virtual ICollection<Table1> Table1s { get;set; }
}

public class Context : DbContext
{
    public Context(string nameOrConnectionString) 
        : base(nameOrConnectionString)
    {
        Roots = Set<Root>();
        Table1s = Set<Table1>();
        Table2s = Set<Table2>();
    }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {          
        var table1 = modelBuilder.Entity<Table1>();
        table1.ToTable("Table1");
        table1.HasKey(r => r.Table1Id);
        table1.HasRequired(r => r.Table2)
            .WithMany(t => t.Table1s)
            .Map(m => m.MapKey("Table2Id"));

        var table2 = modelBuilder.Entity<Table2>();
        table2.ToTable("Table2");
        table2.HasKey(r => r.Table2Id);

        var root = modelBuilder.Entity<Root>();
        root.ToTable("Root");
        root.HasKey(r => r.RootId);
        root.HasRequired(r => r.Table1)
            .WithMany(t => t.Roots)
            .Map(m => m.MapKey("Table1Id"));

        // TODO: Some sort of mapping            

        base.OnModelCreating(modelBuilder);
    }

    public DbSet<Root> Roots { get; private set; }
    public DbSet<Table1> Table1s { get; private set; }
    public DbSet<Table2> Table2s{ get; private set; }
}

最终我想运行这段代码(在一个空数据库上)......

using(var c = new Context(@"connection string"))
{
    c.Roots.Add(new Root
    {
        Table1 = new Table1
        {
            Name = "Test1",
            Table2 = new Table2 { Name = "Test2" }
        }
    });
    c.SaveChanges();
}

然后数据看起来像这样:

Table2
======
Table2Id |  Name
       1 | Test2

Table1
=======
Table1Id |  Name
       1 | Test1

Root
====
RootId | Table1Id | Table2Id
1      |        1 |        1

那么,我该如何进行这样的映射呢? 我查看了 Map 函数和 Property 函数,但我无法理解我应该把什么放在哪里,或者即使它们是合适的?

4

2 回答 2

3

我不想在我的 Root 对象上为 Table2 设置一个属性,而是希望从 Table1 的相关 Table2 中填充该 ID。

EF 不支持这个。您不能将关系中的属性值转发到主表。Table2您必须在 on或 on 上公开导航属性,Root并以与Table1.

于 2012-07-11T20:21:26.373 回答
3

感谢@Ladislav Mrnka 指出它不受支持并且我需要一个导航属性,我决定我可以拥有一个私有导航属性,该属性遵循 Table1.Table2 属性并隐藏 ickyness。所以...

我像这样在我的 Root 类上定义了一个私有导航属性(注意它不存储任何东西,只是遵循 Table1.Table2 属性):

public class Root
{
    public int RootId { get; set; }
    public Table1 Table1 { get; set; }
    private Table2 Table2
    {
        get { return Table1.Table2; }
        set { Table1.Table2 = value; }
    }
}

来自问题:Entity Framework 4 - Mapping non-public properties with CTP5 (code first) in an persistence unware context我创建了这个小助手(这只是意味着我可以获得私有属性的 lambda 表达式):

public interface IObjectExpressionCreator<T>
{
    Expression<Func<T, TResult>> Property<TResult>(string name);
}

public static class PropertyExpression
{
    private class ObjectExpressionCreator<T> : IObjectExpressionCreator<T>
    {
        public Expression<Func<T, TResult>> Property<TResult>(string name)
        {
            var p = Expression.Parameter(typeof(T),
                                         "propertyOrFieldContainer");

            var body = Expression.PropertyOrField(p, name);

            var lambda = Expression.Lambda(typeof(Func<T, TResult>),
                                           body,
                                           p);

            return (Expression<Func<T, TResult>>)lambda;
        }
    }
    public static IObjectExpressionCreator<T> For<T>()
    {
        return new ObjectExpressionCreator<T>();
    }
}

现在我像这样执行映射:

root
    .HasRequired(PropertyExpression.For<Root>().Property<Table2>("Table2"))
    .WithMany()
    .Map(m => m.MapKey("Table2Id"));

当我运行问题中的代码时,我得到了我想要的。

于 2012-07-12T08:10:40.580 回答