LINQ to SQL - 使用抽象基类时的映射异常 [英] LINQ to SQL - mapping exception when using abstract base classes

查看:22
本文介绍了LINQ to SQL - 使用抽象基类时的映射异常的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Problem: I would like to share code between multiple assemblies. This shared code will need to work with LINQ to SQL-mapped classes.

我在此处遇到了同样的问题,但我也遇到过找到了一个我觉得麻烦的解决方法(我不会说错误").

I've encountered the same issue found here, but I've also found a work-around that I find troubling (I'm not going so far as to say "bug").

以下所有代码都可以在本方案下载.

鉴于此表:

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 映射:

and this DBML mapping:

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

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

I've created the following base classes in one assembly "Shared":

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"中被引用,如下所示:

These classes are referenced in another assembly "Main", like so:

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

    }
}

DBML 文件也位于主"程序集中.

The DBML file is located in the "Main" assembly, as well.

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

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

System.InvalidOperationException: Class member UserBase.Name is unmapped.

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

However, the other two base static methods work.

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

Furthermore, the SQL generated by calling User.FindByName_Works(db, "test") is what we were hoping for in the broken call:

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 感知代码?

While I am willing to use this 1 == 1 "hack" for single predicate queries, is there a better way of sharing LINQ to SQL-aware code in a base/shared/core assembly?

推荐答案

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

I have encountered this problem many times in the past because we have a similar architecture in a framework that we use in our company. You may have noticed that if you use the declarative style LINQ queries you'll not encounter this problem. For example the following code will work:

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

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

However, since we are using dynamic filter expressions we couldn't use this method. The alternative solution is to use something like this:

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

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

This solution solved our problem since we can inject a ".Select(i => i)" to the beginning of almost all expressions. This will cause the Linq engine not to look at the base class for the mappings and will force it to look at the actual entity class and find the mappings.

希望能帮到你

这篇关于LINQ to SQL - 使用抽象基类时的映射异常的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆