21

问题:我想在多个程序集之间共享代码。此共享代码需要与 LINQ to SQL 映射的类一起使用。

我在这里遇到了同样的问题,但我也找到了一个我觉得麻烦的解决方法(我不会说“错误”)。

以下所有代码都可以在此解决方案中下载。

鉴于此表:

create table Users
(
      Id int identity(1,1) not null constraint PK_Users primary key
    , Name nvarchar(40) not null
    , Email nvarchar(100) not null
)

和这个 DBML 映射:

<Table Name="dbo.Users" Member="Users">
  <Type Name="User">
    <Column Name="Id" Modifier="Override" Type="System.Int32" DbType="Int NOT NULL IDENTITY" IsPrimaryKey="true" IsDbGenerated="true" CanBeNull="false" />
    <Column Name="Name" Modifier="Override" Type="System.String" DbType="NVarChar(40) NOT NULL" CanBeNull="false" />
    <Column Name="Email" Modifier="Override" Type="System.String" DbType="NVarChar(100) NOT NULL" CanBeNull="false" />
  </Type>
</Table>

我在一个“共享”程序集中创建了以下基类:

namespace TestLinq2Sql.Shared
{
    public abstract class UserBase
    {
        public abstract int Id { get; set; }
        public abstract string Name { get; set; }
        public abstract string Email { get; set; }
    }

    public abstract class UserBase<TUser> : UserBase where TUser : UserBase
    {
        public static TUser FindByName_Broken(DataContext db, string name)
        {
            return db.GetTable<TUser>().FirstOrDefault(u => u.Name == name);
        }

        public static TUser FindByName_Works(DataContext db, string name)
        {
            return db.GetTable<TUser>().FirstOrDefault(u => u.Name == name && 1 == 1);
        }

        public static TUser FindByNameEmail_Works(DataContext db, string name, string email)
        {
            return db.GetTable<TUser>().FirstOrDefault(u => u.Name == name || u.Email == email);
        }
    }
}

这些类在另一个程序集“Main”中引用,如下所示:

namespace TestLinq2Sql
{
    partial class User : TestLinq2Sql.Shared.UserBase<User>
    {

    }
}

DBML 文件也位于“Main”程序集中。

调用时User.FindByName_Broken(db, "test"),抛出异常:

System.InvalidOperationException:类成员 UserBase.Name 未映射。

但是,其他两个基本静态方法有效。

此外,调用生成的 SQLUser.FindByName_Works(db, "test")正是我们在中断调用中所希望的:

SELECT TOP (1) [t0].[Id], [t0].[Name], [t0].[Email]
FROM [dbo].[Users] AS [t0]
WHERE [t0].[Name] = @p0
-- @p0: Input NVarChar (Size = 4; Prec = 0; Scale = 0) [test]

虽然我愿意将此1 == 1“hack”用于单个谓词查询,但是否有更好的方法在基本/共享/核心程序集中共享 LINQ to SQL 感知代码?

4

5 回答 5

19

我过去曾多次遇到过这个问题,因为我们在我们公司使用的框架中有类似的架构。您可能已经注意到,如果您使用声明式风格的 LINQ 查询,您将不会遇到这个问题。例如,以下代码将起作用:

return (from i in db.GetTable<TUser>() where i.Name = "Something").FirstOrDefault();

但是,由于我们使用的是动态过滤器表达式,我们不能使用这种方法。另一种解决方案是使用这样的东西:

return db.GetTable<TUser>().Select(i => i).Where(i => i.Name == "Something").SingleOrDefault();

这个解决方案解决了我们的问题,因为我们可以在几乎所有表达式的开头注入“.Select(i => i)”。这将导致 Linq 引擎不查看映射的基类,并强制它查看实际的实体类并找到映射。

希望能帮助到你

于 2009-07-01T10:58:19.603 回答
5

尝试在 Where 子句之前包含 OfType

return _dbContext.GetTable<T>().OfType<T>().Where(expression).ToList();

于 2013-07-18T21:42:57.080 回答
3

我很幸运在共享程序集中定义数据类并在许多程序集中使用它们,而不是将许多程序集的数据类映射到共享合同。使用您的示例命名空间,将自定义 DataContext 和您的共享数据类放在 TestLinq2Sql.Shared 中:

namespace TestLinq2Sql.Shared
{
    public class SharedContext : DataContext
    {
        public Table<User> Users;
        public SharedContext (string connectionString) : base(connectionString) { }
    }

    [Table(Name = "Users")]
    public class User
    {
        [Column(DbType = "Int NOT NULL IDENTITY", IsPrimaryKey=true, CanBeNull = false)]
        public int Id { get; set; }

        [Column(DbType = "nvarchar(40)", CanBeNull = false)]
        public string Name { get; set; }

        [Column(DbType = "nvarchar(100)", CanBeNull = false)]
        public string Email { get; set; }
    }
}

然后使用来自任何其他程序集的 DataContext:

using (TestLinq2Sql.Shared.SharedContext shared = 
    new TestLinq2Sql.Shared.SharedContext(
        ConfigurationManager.ConnectionStrings["myConnString"].ConnectionString))
{
    var user = shared.Users.FirstOrDefault(u => u.Name == "test");
}  
于 2009-06-29T05:14:15.710 回答
3

这看起来像一个错误 - 我们将主键上的特殊情况 Single 进行本地查找,但看起来此代码路径没有正确获取元数据。

1=1 hack 将意味着它通过正常的数据库往返,但实际上应该提交一个错误......

于 2009-07-23T02:50:23.993 回答
0

你在这里问了几个问题 Jarrod,你能更具体一点吗?也就是说,您是否只想知道您的方法失败的原因?或者,也许您想要一种在不同项目中使用数据对象的方法?我假设您没有尝试将 LINQ to SQL 用作数据库映射层,而是将其用作域模型?在这种情况下,两个应用程序是否实现相同的域(业务流程、验证等)?

于 2009-06-24T10:59:24.853 回答