3

SQL Server2012データベースに対してEntityFramework(バージョン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)

ここで興味深いのは、 Table2のRootオブジェクトにプロパティが必要ないことです。代わりに、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

Table2のRootオブジェクトにプロパティは必要ありません。代わりに、Table1の関連するTable2からそのIDを入力する必要があります。

EFはこれをサポートしていません。リレーションからメインテーブルにプロパティ値を転送することはできません。ナビゲーションプロパティを上Table2または上に公開Rootし、の場合と同じ方法でマップする必要がありますTable1

于 2012-07-11T20:21:26.373 に答える
3

@Ladislav Mrnka がサポートされていないこと、およびナビゲーション プロパティが必要であることを指摘してくれたおかげで、私が決定したのは、Table1.Table2 プロパティに従い、不快感を隠すプライベート ナビゲーション プロパティを持つことができるということでした。そう...

次のように、ルート クラスにプライベートナビゲーション プロパティを定義しました(何も格納しないことに注意してください。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 - 永続性を認識しないコンテキストで非公開プロパティを CTP5 (コードが最初) にマッピングするこの小さなヘルパーを作成しました (これは、プライベート プロパティのラムダ式を取得できることを意味します):

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 に答える