4

私はEntity Frameworkを初めて使用し、一部のレガシーデータアクセスコードをEFを使用するように変換することを調査しています。EFで次のことが可能かどうか、可能であればその方法を知りたいです。このような Customer テーブルがあるとします

CustomerId | ProductId | StartDate | EndDate
--------------------------------------------
100        | 999       | 01/01/2012| null

また、製品オブジェクトのキャッシュとして、別の場所 (XML ファイルなど) から製品データを読み込むとします。

public class Customer
{
    public int CustomerId {get;set;}
    public int Product {get;set}
    public DateTime StartDate {get;set;}
    public DateTime? EndDate {get;set;}    

}

public class Product
{
    public int ProductId {get;set;}
    public int Description {get;set}
}

現在、CustomerDal クラスでは、メソッドは StoredProc を使用して、このような Customer オブジェクトを取得します

Customer GetCustomer(int customerId)
{
    // setup connection, command, parameters for SP, loop over datareader
    Customer customer = new Customer();
    customer.CustomerId = rdr.GetInt32(0);
    int productId = rdr.GetInt32(1);
    // ProductCache is a singleton object that has been initialised before
    customer.Product = ProductCache.Instance.GetProduct(productId);
    customer.StartDate = rdr.GetDateTime(2);
    customer.EndDate = rdr.IsDbNull(3) ? (DateTime?)null : rdr.GetDateTime(3);
    return customer;
}

私の質問は、DB からではなく別の方法で、この場合はメモリ内キャッシュから Product プロパティを設定する Customer オブジェクトを具体化するときに EF を使用してこれが可能であるということです。同様に、新しい Customer オブジェクトを保存すると、Products プロパティから ProductId のみが取得され、値が DB に保存されます。

4

1 に答える 1

0

製品インスタンスを EF コンテキストにアタッチすると、顧客に関連付けられている製品が既にアタッチされている限り、データベースへのクエリなしでプロパティがメモリから自動的に読み込まCustomerれます。Product

たとえば、次のエンティティから始めます。

public class Customer
{
    public int Id { get; set; }
    public int ProductId { get; set; }
    public string Name { get; set; }
    public Product Product { get; set; }
}

public class Product
{
    public int Id { get; set; }
    public string Description { get; set; }
}

簡単にするために、製品はグローバルに利用可能になります。静的クラスにしましょう。

public static class CachedProducts
{
    public static Product[] All
    {
        get
        {
            return new Product[] { new Product { Id = 1, Description = "Foo" } };
        }
    }
}

これを念頭に置いて、すべての EF コンテキストがそれに接続されているすべての製品で始まることを保証する必要があります。

public class CustomerContext : DbContext
{
    public CustomerContext()
    {
        // Attach products to context
        Array.ForEach(CachedProducts.All, p => this.Products.Attach(p));
    }
    public DbSet<Customer> Customers { get; set; }
    public DbSet<Product> Products { get; set; }
}

最後に、サンプルを完成させて実行可能にするために、データベースをシードし、顧客にリクエストして、関連する製品の説明を出力します。

public class DatabaseInitializer : CreateDatabaseIfNotExists<CustomerContext>
{
    protected override void Seed(CustomerContext context)
    {
        var p = new Product { Id = 1, Description = "Foo" };
        var c = new Customer { Id = 1, Product = p, Name = "John Doe" };

        context.Customers.Add(c);
        context.SaveChanges();
    }
}


class Program
{
    static void Main(string[] args)
    {
        Database.SetInitializer<CustomerContext>(new DatabaseInitializer());

        using (var context = new CustomerContext())
        {
            var customer = context.Customers.Single(c => c.Id == 1);

            Console.WriteLine(customer.Product.Description);
        }
    }
}

プロファイラーを SQL Server にアタッチすると、顧客がデータベースから読み込まれますが、製品は既にコンテキストにアタッチされているため、製品を取得するためのクエリは実行されません。これは、顧客をロードするときと、関連する製品で新しい顧客を保存するときに機能します。

免責事項:私は EF の専門家ではないため、このアプローチには、考慮できない望ましくない副作用がある可能性があります。

于 2012-07-06T22:38:35.527 に答える