Неожиданное поведение с запросом с несколькими сопоставлениями с использованием Dapper.net - PullRequest
5 голосов
/ 15 июля 2011

Я только начал изучать 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();

Когда это выполняется, не все свойства заполняются (несмотря на одинаковые имена в таблице БД и в моих объектах.

Я заметил, что если я don't 'выберите p. * и т. д.' в моем SQL, и вместо этого.

Я явно указываю поля.

Я хочу вернуть EXCLUDING p.CategoryId из запроса,тогда все заполняется (за исключением, очевидно, CategoryId для объекта Photo, который я исключил из оператора select).

Но я ожидал бы, что смогу включить это поле в запрос и заполнить его, как и все другие поля, запрошенные в SQL.

Я мог быпросто исключите свойство CategoryId из моего класса Photo и всегда используйте Photo.PhotoCategory.CategoryId, когда мне нужен идентификатор.

Но в некоторых случаях я могу не захотеть заполнять объект PhotoCategory, когда получаюэкземпляр объекта Photo.

Кто-нибудь знает, почему происходит вышеупомянутое поведение?Это нормально для Dapper?

Ответы [ 3 ]

5 голосов
/ 19 июля 2011

Я только что исправил это:

    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 ... И ... использовалось в качестве точки разделения.

Для преодоления теперь щегольского допускается, чтобы поле Id отображалось в любом месте первого типа. Проиллюстрировать.

Скажем, у нас есть:

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

Старый метод расщепления не учитывал фактический базовый тип, который он отображал. Так что ... это сопоставлено Id => A и FooId, FooId, Name => B

Новый новый метод знает о реквизитах и ​​полях в A. Когда он впервые встречает FooId в потоке, он не начинает разделение, поскольку он знает, что A имеет свойство с именем FooId, которое необходимо отобразить, в следующий раз, когда он увидит FooId, оно будет разделено, что приведет ожидаемые результаты.

0 голосов
/ 07 февраля 2014

Я знаю, что этот вопрос старый, но подумал, что сэкономлю кому-то 2 минуты с очевидным ответом на это: просто псевдоним одного идентификатора из одной таблицы:

е:

SELECT
    user.Name, user.Email, user.AddressId As id, address.*
FROM 
    User user
    Join Address address
    ON user.AddressId = address.AddressId
0 голосов
/ 15 июля 2011

У меня похожая проблема.Это связано с тем, что и дочерний элемент, и родительский элемент имеют одинаковое имя для поля, на которое делится поле.Для примера работает следующее:

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» используется в обеих таблицах и обоих объектах.этот сценарий.Думаю, это описывает проблему, но есть ли решение / обходной путь, который мы можем использовать (кроме проектных решений OO)?

...