4

我对 Entity Framework 相当陌生,并且正在研究将一些遗留数据访问代码转换为使用 EF。我想知道在 EF 中是否可以执行以下操作,如果可以,如何操作。假设我有一个这样的客户表

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;
}

我的问题是,当它实现 Customer 对象时,这可能使用 EF,它设置 Product 属性不是来自数据库,而是通过另一种方法,在这种情况下来自内存缓存。同样,当保存一个新的客户对象时,它只从 Products 属性中获取 ProductId 并将值保存在 DB 中。

4

1 回答 1

0

如果您将产品实例附加到 EF 上下文,则在加载属性时,只要与客户关联的产品已经附加,就会自动从内存中填充属性,而无需查询数据库CustomerProduct

例如,从这些实体开始:

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 回答