现在的位置: 首页 > 综合 > 正文

光脚丫学LINQ(038):隐藏联接表实体类的跨越而直接访问多对多关系数据

2012年05月23日 ⁄ 综合 ⁄ 共 4619字 ⁄ 字号 评论关闭

视频演示:http://u.115.com/file/f223235faf

演示重点说明
在前一个演示中,我们通过使用两个一对多的关系建立了LINQ to SQL中的伪多对多关系,之所以称之为伪关系,只是表示它并非是真正意义上的多对多关系。然而,前面的做法却给使用对象模型的调用方带来了一点小小的麻烦。因为,调用方无论是从两个实体类的哪一方去获取另外一方关联数据的时候,都必须显示的跨越实体类对象。这难道不让人觉得很麻烦吗?在这个演示中,我们要实现的效果,就是把这个链接表的实体类对象给隐藏起来。
具体要实现的效果是这样的:通过实体类的某个集合属性直接来获取与之关联的另一方实体类的对象。当然,这个方案仍然是基于上一个方案的,只是我们得想点办法把链接表实体类给隐藏起来。
在本演示中,最终实现的结果则是这样的:通过Customer.Products属性直接获取客户订购的所有产品数据,而通过Product.Customers属性来获取订购当前产品的所有客户数据。

没有进行修改之前的对象模型
下面的代码是没有进行修改前的对象模型,也就是上个演示所建立的对象模型,只贴出重点代码,完整的代码已经和演示视频一起打包,可以下载查看。

Customer.cs

[Table(Name = "Customers")]
public class Customer
{
    [Column(Name = "CustomerID", IsPrimaryKey = true)]
    public string CustomerID;

    private EntitySet<CustomerProduct> _CustomerProducts;
    [Association(Storage = "_CustomerProducts", ThisKey = "CustomerID", OtherKey = "CustomerID")]
    public EntitySet<CustomerProduct> CustomerProducts
    {
        get { return this._CustomerProducts; }
        set { this._CustomerProducts.Assign(value); }
    }
}

Product.cs

CustomerProduct.cs

[Table(Name = "CustomersProducts")]
public class CustomerProduct
{
    private EntityRef<Customer> _Customer;
    [Association(Storage = "_Customer", ThisKey = "CustomerID", OtherKey = "CustomerID")]
    public Customer Customer
    {
        get { return this._Customer.Entity; }
        set { this._Customer.Entity = value; }
    }

    private EntityRef<Product> _Product;
    [Association(Storage = "_Product", ThisKey = "ProductID", OtherKey = "ProductID")]
    public Product Product
    {
        get { return this._Product.Entity; }
        set { this._Product.Entity = value; }
    }
}

从上面的示例代码来看,Customer实体类是没有Products属性,Product实体类也没有Customers属性,不是我没有贴上去,而是还没有定义呢。要如何定义呢?看下面的两段代码:
Customer.Products

[Table(Name = "Customers")]
public class Customer
{
    private EntitySet<Product> _Products;

    /// <summary>
    /// 获取当前客户订购的所有产品对象。
    /// </summary>
    public EntitySet<Product> Products
    {
        get
        {
            if (this._Products == null)
                this._Products = new EntitySet<Product>();
            else
                this._Products.Clear();

            foreach (var CPObject in this.CustomerProducts)
            {
                var ProductObject = CPObject.Product;
                this._Products.Add(ProductObject);
            }

            return this._Products;
        }
    }
}


Product.Customers

[Table(Name = "Products")]
public class Product
{
    private EntitySet<Customer> _Customers;

    /// <summary>
    /// 获取订购当前产品的所有客户对象。
    /// </summary>
    public EntitySet<Customer> Customers
    {
        get
        {
            if (this._Customers == null)
                this._Customers = new EntitySet<Customer>();
            else
                this._Customers.Clear();

            foreach (var CPObject in this.ProductCustomers)
            {
                var CustomerObject = CPObject.Customer;
                this._Customers.Add(CustomerObject);
            }

            return this._Customers;
        }
    }
}

把上面这两个属性添加到对应的实体类中就可以了。这些代码是什么意思呢?大家应该一看就明白了。如果实在不明白的话,演示视频中有详细的解说。
有了上面这两个属性,现在就可以通过Customer.Products属性直接访问客户订购的所有产品对象了,也可以直接通过Product.Customers属性直接获取订购此产品的所有客户对象了。实际上还是借助于链接表实体类CustomerProduct,只不过我们把这个信息隐藏到了集合属性中。

接着,调用方再来使用这个对象模型的时候,就简单的多了。如下面的两段测试代码:
直接通过客户对象获取客户订购的所有产品对象:

 *************************************************
 直接通过客户对象获取客户订购的所有产品对象。
 *************************************************
DatabaseDataContext db = new DatabaseDataContext(@"C:\LINQ\Database.mdf");
var AllCustomers = from CustomerObject in db.Customers
                   select CustomerObject;
foreach (var CustomerObject in AllCustomers)
{
    Console.WriteLine("------------------------------------------");
    Console.ForegroundColor = ConsoleColor.Green;
    Console.WriteLine("Customer ID : {0}", CustomerObject.CustomerID);
    Console.ForegroundColor = ConsoleColor.White;
    Console.WriteLine("Customer Name : {0}", CustomerObject.ContactName);

    Thread.Sleep(1000);

    foreach (var ProductObject in CustomerObject.Products)
    {
        Console.WriteLine("     ProductID={0}, ProductName={1}",
            ProductObject.ProductID,
            ProductObject.ProductName);
    }
    Console.WriteLine();

    Thread.Sleep(2000);
}

直接通过产品对象获取订购此产品的所有客户对象:

// *************************************************
// 直接通过产品对象获取订购此产品的所有客户对象。
// *************************************************
DatabaseDataContext db = new DatabaseDataContext(@"C:\LINQ\Database.mdf");
var AllProducts = from ProductObject in db.Products
                  select ProductObject;
foreach (var ProductObject in AllProducts)
{
    Console.WriteLine("------------------------------------------");
    Console.ForegroundColor = ConsoleColor.Green;
    Console.WriteLine("Product ID : {0}", ProductObject.ProductID);
    Console.ForegroundColor = ConsoleColor.White;
    Console.WriteLine("Product Name : {0}", ProductObject.ProductName);

    Thread.Sleep(1000);

    foreach (var CustomerObject in ProductObject.Customers)
    {
        Console.WriteLine("     CustomerID={0}, ContactName={1}",
            CustomerObject.CustomerID,
            CustomerObject.ContactName);
    }
    Console.WriteLine();

    Thread.Sleep(2000);
}

呵呵,怎么样,是不是变的简单了一些呢?虽然,对象模型增加了一点点的复杂性,但是当调用方调用这个对象模型的时候就变的简单了一些。因此,为对象模型增加的这点复杂性是值得的,因为有时候我们自己就是调用方。更何况使用对象模型的次数远远要比定义对象模型的次数多嘛!^_^

光脚丫思考 2010-10-30

[Table(Name = "Products")]
public class Product
{
    private EntitySet<CustomerProduct> _ProductCustomers;
    [Association(Storage = "_ProductCustomers", ThisKey = "ProductID", OtherKey = "ProductID")]
    public EntitySet<CustomerProduct> ProductCustomers
    {
        get { return this._ProductCustomers; }
        set { this._ProductCustomers.Assign(value); }
    }
}

抱歉!评论已关闭.