Soru LINQ to SQL - soyut temel sınıflarını kullanırken istisnai haritalama


Sorun: Birden çok derlemeler arasında kod paylaşmak istiyorum. Bu paylaşılan kodun SQL eşlemeli sınıflara LINQ ile çalışması gerekecektir.

Aynı sorunla karşılaştım İşteama aynı zamanda bir uğraş buldum da rahatsız edici buluyorum (bugüne kadar "bug" diyemiyorum).

Aşağıdaki kodların tümü indirilebilir bu çözüm.

Bu tablo verildiğinde:

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
)

ve bu DBML eşlemesi:

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

Bir "Paylaşılan" derlemesinde aşağıdaki temel sınıfları oluşturdum:

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

Bu sınıflar, başka bir derlemede "Ana" olarak adlandırılır, şöyle ki:

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

    }
}

DBML dosyası, "Ana" derlemede de bulunur.

Çağırırken User.FindByName_Broken(db, "test"), bir istisna atılır:

System.InvalidOperationException: Sınıf üyesi UserBase.Name unmapped.

Ancak, diğer iki temel statik yöntem çalışır.

Ayrıca, çağırarak oluşturulan SQL User.FindByName_Works(db, "test") kırık aramada umuyorduk:

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]

Bunu kullanmak için istekliyim 1 == 1 Tekli yüklemeler için "kesmek", bir temel / paylaşılan / çekirdek derlemesinde SQL-bilinçli kod için LINQ paylaşmanın daha iyi bir yolu var mı?


21
2018-06-20 09:03


Menşei




Cevaplar:


Bu problemi geçmişte birçok kez karşılaştım çünkü şirketimizde kullandığımız bir çerçevede benzer bir mimariye sahibiz. Tanımlama stili LINQ sorgularını kullanırsanız, bu sorunla karşılaşmayacağınızı fark etmiş olabilirsiniz. Örneğin aşağıdaki kod çalışacaktır:

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

Ancak, dinamik filtre ifadeleri kullandığımız için bu yöntemi kullanamadık. Alternatif çözüm, böyle bir şey kullanmaktır:

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

Bu çözüm, neredeyse tüm ifadelerin başına bir ".Select (i => i)" enjekte edebildiğimiz için problemimizi çözdü. Bu, Linq motorunun eşleştirmeler için temel sınıfa bakmamasına ve gerçek varlık sınıfına bakmaya ve eşlemeleri bulmaya zorlamasına neden olur.

Umarım yardımcı olur


19
2017-07-01 10:58



Herhangi bir yerde yan tümcesi olmayan bir sorgu yapar ve sonra liste bellekte filtrelenir. Pek çok sonuç için iyi değil; - Gandarez


WhereType öğesinden önce dahil etmeyi deneyin.

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


5
2017-07-18 21:42



Wow, benim için çalışan tek çözüm, bunu yayınlamak için çok teşekkürler. - ViRuSTriNiTy


Paylaşılan bir mecliste veri sınıflarını tanımlayan ve birçok meclisin veri sınıflarını ortak bir sözleşmeye eşleştiren birçok mecliste tüketme şansım oldu. Örnek ad alanlarınızı kullanarak, özel bir DataContext ve paylaşılan veri sınıflarınızı TestLinq2Sql.Shared'e yerleştirin:

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

Sonra DataContext'i başka bir meclisten tüketin:

using (TestLinq2Sql.Shared.SharedContext shared = 
    new TestLinq2Sql.Shared.SharedContext(
        ConfigurationManager.ConnectionStrings["myConnString"].ConnectionString))
{
    var user = shared.Users.FirstOrDefault(u => u.Name == "test");
}  

3
2018-06-29 05:14





Bu bir hata gibi görünüyor - biz yerel bir arama yapmak için bir birincil anahtar tek özel durum Tek ama bu kod yolu meta verileri düzgün kapma gibi görünüyor.

1 = 1 kesmek normal bir veritabanı gidiş-dönüşünden geçeceği anlamına gelecektir ama gerçekten bir hata dosyalanmalıdır ...


3
2017-07-23 02:50



Aslında, mevcut bir hata raporu gibi görünüyor - "Kapalı, Başarısız Ol" durumu ile. :( connect.microsoft.com/VisualStudio/feedback/... - daveidmx


Burada birkaç soru soruyorsun Jarrod, daha spesifik olabilir misin? Yani, sadece yönteminizin neden başarısız olduğunu bilmek ister misiniz? Ya da farklı projeler arasında veri nesneleri kullanmanın bir yolunu mu istiyorsunuz? LINQ'ı bir veritabanı eşleme katmanı olarak SQL'e kullanmaya çalıştığınızı ve bunu bir etki alanı modeli olarak kullandığınızı varsayıyorum. Bu durumda, her iki uygulama da aynı alanı uygular (iş süreçleri, doğrulama, vb.)?


0
2018-06-24 10:59