您的位置:知识库 » 数据库

在LINQ to SQL中使用Translate方法以及修改查询用SQL

作者: Jeffrey Zhao  来源: 博客园  发布时间: 2008-09-20 23:37  阅读: 6304 次  推荐: 0   原文链接   [收藏]  
摘要:老赵在最近的项目中使用了LINQ to SQL作为数据层的基础,在LINQ to SQL开发方面积累了一定经验,也总结出了一些官方文档上并未提及的有用做法,特此和大家分享。
[1] 引入
[2] 使用Translate方法1
[3] 使用Translate方法2
[4] 改变LINQ to SQL所执行的SQL语句
[5] 扩展所受的限制

 

新的ExecuteQuery方法很容易使用:

public static List<Item> GetItemsForListing(int ownerId)
{
    ItemDataContext dataContext = new ItemDataContext();
    var query = from item in dataContext.Items
                where item.UserID == ownerId
                orderby item.CreateTime descending
                select new
                {
                    ItemID = item.ItemID,
                    Title = item.Title,
                    CreateTime = item.CreateTime,
                    UserID = item.UserID
                };

    using (dataContext.Connection)
    {
        return dataContext.ExecuteQuery<Item>(query);
    }
}

在通过LINQ to SQL获得一个query之后,我们不再直接获得查询数据了,而是将其交给我们的ExecuteQuery扩展来执行。现在这种做法既保证了使用LINQ to SQL进行查询,又构造出Item对象的部分字段,算是一种较为理想的解决方案。不过使用这个方法来获得仅有部分字段的对象时需要注意一点:在构造匿名对象时使用的属性名,可能和目标实体对象(例如之前的Item)的属性名并非一一对应的关系。

这种情况会在实体对象的属性名与数据表字段名不同的时候发生。在使用LINQ to SQL时默认生成的实体对象,其属性名与数据库的字段名完全对应,这自然是最理想的情况。但是有些时候我们的实体对象属性名和数据库字段名不同,这就需要在ColumnAttribute标记中设置Name参数了(当然,如果使用XmlMappingSource的话也可以设置),如下:

[Table(Name = "dbo.Item")]
public partial class Item : INotifyPropertyChanging, INotifyPropertyChanged
{
    [Column(Storage = "_OwnerID", DbType = "Int NOT NULL", Name = "UserID")]
    public int OwnerID { get { } set { } }
}

OwnerID属性上标记的ColumnAttribute的Name属性设为UserID,这表示它将与Item表中的UserID字段对应。那么如果我们要在这种情况下改写之前的GetItemsForListing方法,我们该怎么做呢?可能有朋友会很自然的想到:

public static List<Item> GetItemsForListing(int ownerId)
{
    ItemDataContext dataContext = new ItemDataContext();
    var query = from item in dataContext.Items
                where item.OwnerID == ownerId
                orderby item.CreateTime descending
                select new
                {
                    ItemID = item.ItemID,
                    Title = item.Title,
                    CreateTime = item.CreateTime,
                    OwnerID = item.OwnerID
                };

    using (dataContext.Connection)
    {
        return dataContext.ExecuteQuery<Item>(query);
    }
}

按照“常理”判断,似乎只要将所有的UserID改为OwnerID即可——其实不然。查看方法返回的结果就能知道,所有对象的OwnerID的值都是默认值“0”,这是怎么回事呢?使用SQL Profiler观察以上代码所执行SQL语句之后我们便可明白一切:

SELECT [t0].[ItemID], [t0].[Title], [t0].[CreateTime][t0].[UserID] AS [OwnerID]
FROM [dbo].[Item] AS [t0]
WHERE [t0].[UserID] = @p0
ORDER BY [t0].[CreateTime] DESC

由于我们所使用的query实际上是用于生成一系列匿名对象的,而这些匿名对象所包含的是“OwnerID”而不是“UserID”,因此LINQ to SQL实际在生成SQL语句的时候会将UserID字段名转换成OwnerID。由于Item的OwnerID上标记的ColumnAttribute把Name设置成了UserID,所以Translate方法读取DbDataReader对象时事实上会去寻找UserID字段而不是OwnerID字段——这很显然就造成了目前的问题。因此,如果您使用了ColumnAttribute中的Name属性改变了数据库字段名与实体对象属性名的映射关系,那么在创建匿名对象的时候还是要使用数据库的字段名,而不是实体对象名,如下:

public static List<Item> GetItemsForListing(int ownerId)
{
    ItemDataContext dataContext = new ItemDataContext();
    var query = from item in dataContext.Items
                where item.OwnerID == ownerId
                orderby item.CreateTime descending
                select new
                {
                    ItemID = item.ItemID,
                    Title = item.Title,
                    CreateTime = item.CreateTime,
                    UserID = item.OwnerID
                };

    using (dataContext.Connection)
    {
        return dataContext.ExecuteQuery<Item>(query);
    }
}

这样就能解决问题了——不过显得不很漂亮,因此在使用LINQ to SQL时,我建议保持实体对象属性名与数据库字段名之间的映射关系。

0
0
 
标签:LINQ to SQL

数据库热门文章

    数据库最新文章

      最新新闻

        热门新闻