簡體   English   中英

使用 Dapper.net 的多映射查詢的意外行為

[英]Unexpected behaviour with a multi-mapping query using Dapper.net

我才剛剛開始查看 Dapper.net,並且剛剛嘗試了一些不同的查詢,其中一個查詢產生了我沒想到的奇怪結果。

我有 2 個表 - Photos & PhotoCategories ,其中與CategoryID相關

照片表

PhotoId (PK - int)  
CategoryId (FK - smallint)  
UserId (int)

照片類別表

CategoryId (PK - smallint)  
CategoryName (nvarchar(50))

我的 2 節課:

public class Photo
{
    public int PhotoId { get; set; }
    public short CategoryId { get; set; }
    public int UserId { get; set; }
    public PhotoCategory PhotoCategory { get; set; }
}

public class PhotoCategory
{
    public short CategoryId { get; set; }
    public string CategoryName { get; set; }
{

我想使用多重映射來返回Photo的實例,以及相關PhotoCategory的填充實例。

var sql = @"select p.*, c.* from Photos p inner 
            join PhotoCategories c 
            on p.CategoryID = c.CategoryID where p.PhotoID = @pid";

cn.Open();
var myPhoto = cn.Query<Photo, PhotoCategory, Photo>(sql, 
               (photo, photoCategory) => { photo.PhotoCategory = photoCategory; 
                                           return photo; }, 
               new { pid = photoID }, null, true, splitOn: "CategoryID").Single();

執行此操作時,並非所有屬性都被填充(盡管 DB 表和我的對象之間的名稱相同。

我注意到如果我don't “選擇 p.* 等” 在我的SQL中,而不是。

我明確 state 字段。

我想從查詢中返回EXCLUDING p.CategoryId ,然后所有內容都會被填充(顯然 CategoryId 與我已從 select 語句中排除的照片 object 除外)。

但我希望能夠在查詢中包含該字段,並擁有它,以及在SQL中查詢的所有其他字段,以便填充。

我可以從我的Photo class 中排除CategoryId屬性,並在需要 ID 時始終使用Photo.PhotoCategory.CategoryId

但在某些情況下,當我獲得 Photo object 的實例時,我可能不想填充PhotoCategory object。

有誰知道為什么會發生上述行為? 這對 Dapper 來說正常嗎?

我剛剛對此進行了修復:

    class Foo1 
    {
        public int Id;
        public int BarId { get; set; }
    }

    class Bar1
    {
        public int BarId;
        public string Name { get; set; }
    }

    public void TestMultiMapperIsNotConfusedWithUnorderedCols()
    {

        var result = connection.Query<Foo1,Bar1,
                      Tuple<Foo1,Bar1>>(
                         "select 1 as Id, 2 as BarId, 3 as BarId, 'a' as Name",
                         (f,b) => Tuple.Create(f,b), splitOn: "BarId")
                         .First();

        result.Item1.Id.IsEqualTo(1);
        result.Item1.BarId.IsEqualTo(2);
        result.Item2.BarId.IsEqualTo(3);
        result.Item2.Name.IsEqualTo("a");

    }

如果first一種類型中有一個字段,那么多映射器會感到困惑,而second類型也恰好是......並且......被用作分割點。

現在要克服 dapper 允許Id字段顯示在第一種類型的任何位置。 為了顯示。

假設我們有:

classes: A{Id,FooId} B{FooId,Name}
splitOn: "FooId"
data: Id, FooId, FooId, Name

舊的拆分方法沒有考慮它映射的實際底層類型。 所以...它映射了Id => AFooId, FooId, Name => B

新方法知道A中的道具和字段。 當它第一次遇到FooId中的 FooId 時,它不會開始拆分,因為它知道A有一個名為FooId的屬性需要映射,下次它看到FooId時它會拆分,從而產生預期的結果。

我知道這個問題很老,但我想我會用明顯的答案為某人節省 2 分鍾:只需從一張表中取一個 id 的別名:

IE:

SELECT
    user.Name, user.Email, user.AddressId As id, address.*
FROM 
    User user
    Join Address address
    ON user.AddressId = address.AddressId

我有一個類似的問題。 這與子項和父項對於要拆分的字段具有相同名稱的事實有關。 以下示例有效:

class Program
{
    static void Main(string[] args)
    {
        var createSql = @"
            create table #Users (UserId int, Name varchar(20))
            create table #Posts (Id int, OwnerId int, Content varchar(20))

            insert #Users values(99, 'Sam')
            insert #Users values(2, 'I am')

            insert #Posts values(1, 99, 'Sams Post1')
            insert #Posts values(2, 99, 'Sams Post2')
            insert #Posts values(3, null, 'no ones post')
        ";

        var sql =
        @"select * from #Posts p 
        left join #Users u on u.UserId = p.OwnerId 
        Order by p.Id";

        using (var connection = new SqlConnection(@"CONNECTION STRING HERE"))
        {
            connection.Open();
            connection.Execute(createSql);

            var data = connection.Query<Post, User, Post>(sql, (post, user) => { post.Owner = user; return post; }, splitOn: "UserId");
            var apost = data.First();

            apost.Content = apost.Content;
            connection.Execute("drop table #Users drop table #Posts");
        }
    }
}

class User
{
    public int UserId { get; set; }
    public string Name { get; set; }
}
class Post
{
    public int Id { get; set; }
    public int OwnerId { get; set; }
    public User Owner { get; set; }
    public string Content { get; set; }
}

但以下不是因為在兩個表和兩個對象中都使用了“UserId”。

class Program
{
    static void Main(string[] args)
    {
        var createSql = @"
            create table #Users (UserId int, Name varchar(20))
            create table #Posts (Id int, UserId int, Content varchar(20))

            insert #Users values(99, 'Sam')
            insert #Users values(2, 'I am')

            insert #Posts values(1, 99, 'Sams Post1')
            insert #Posts values(2, 99, 'Sams Post2')
            insert #Posts values(3, null, 'no ones post')
        ";

        var sql =
        @"select * from #Posts p 
        left join #Users u on u.UserId = p.UserId 
        Order by p.Id";

        using (var connection = new SqlConnection(@"CONNECTION STRING HERE"))
        {
            connection.Open();
            connection.Execute(createSql);

            var data = connection.Query<Post, User, Post>(sql, (post, user) => { post.Owner = user; return post; }, splitOn: "UserId");
            var apost = data.First();

            apost.Content = apost.Content;
            connection.Execute("drop table #Users drop table #Posts");
        }
    }
}

class User
{
    public int UserId { get; set; }
    public string Name { get; set; }
}
class Post
{
    public int Id { get; set; }
    public int UserId { get; set; }
    public User Owner { get; set; }
    public string Content { get; set; }
}

在這種情況下,Dapper 的映射似乎變得非常混亂。 認為這描述了問題,但是我們可以采用解決方案/解決方法(除了 OO 設計決策)嗎?

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM