【问题标题】:Dapper and anonymous TypesDapper 和匿名类型
【发布时间】:2011-09-03 01:52:05
【问题描述】:

Dapper 可以使用匿名类型吗?

我可以看到你如何使用动态,即

connection.Query<dynamic>(blah, blah, blah) 

那么是否可以做一个

.Select(p=> new { A, B ,C }) 

或者之后的一些变化?

编辑

我想我会向您展示我目前是如何使用 Dapper 的。我倾向于缓存(使用 InMemoryCache)数据,所以我只在开始时执行一个大查询(使用 Dapper 非常快),然后我使用 Linq 在我的存储库中对其进行排序。

using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data.Common;
using System.Linq;
using Dapper;

namespace SomeNamespace.Data
{
public class DapperDataContext : IDisposable
{
    private readonly string _connectionString;
    private readonly DbProviderFactory _provider;
    private readonly string _providerName;

    public DapperDataContext()
    {
        const string connectionStringName = " DataContextConnectionString";
        _connectionString = ConfigurationManager.ConnectionStrings[connectionStringName].ConnectionString;
        _providerName = ConfigurationManager.ConnectionStrings[connectionStringName].ProviderName;
        _provider = DbProviderFactories.GetFactory(_providerName);
    }

    public IEnumerable<MyDataView> MyData1 { get; private set; }
    public IEnumerable<MyDataView> MyData2 { get; private set; }

    protected string SqlSelectMyTable1Query
    {
        get
        {
            return @"SELECT Id, A, B, C from table1Name";
        }
    }   


protected string SqlSelectMyTable2Query
{
    get
    {
    return @"SELECT Id, A, B, C from table2Name";
    }
    }

    public void Dispose()
    {
    }

    public void Refresh()
    {
        using (var connection = _provider.CreateConnection())
        {
            // blow up if null
            connection.ConnectionString = _connectionString;
            connection.Open();

            var sql = String.Join(" ",
                            new[]
                                {
                                    SqlSelectMyTable1Query,
                                    SqlSelectMyTable2Query
                                });

            using (var multi = connection.QueryMultiple(sql))
            {
                MyData1 = multi.Read<MyDataView>().ToList();
                MyData2 = multi.Read<MyDataView>().ToList();
            }
        }
    }

    public class MyDataView
    {
        public long Id { get; set; }
        public string A { get; set; }
        public string B { get; set; }
        public string C { get; set; }
    }      
}
}

InMemoryCache 看起来像这样

namespace Libs.Web
{
public class InMemoryCache : ICacheService
{
    #region ICacheService Members

    public T Get<T>(string cacheId, Func<T> getItemCallback) where T : class
    {
        var item = HttpRuntime.Cache.Get(cacheId) as T;
        if (item == null)
        {
            item = getItemCallback();
            HttpContext.Current.Cache.Insert(cacheId, item);
        }
        return item;
    }

    public void Clear(string cacheId)
    {
        HttpContext.Current.Cache.Remove(cacheId);
    }

    #endregion
}

public interface ICacheService
{
    T Get<T>(string cacheId, Func<T> getItemCallback) where T : class;
    void Clear(string cacheId);
}
}

【问题讨论】:

  • 是的,我有点期待这种事情,但目前我没有得到快乐 var result = multi.Read().Select((p)=> new {Id = p[ "Id"]}).ToList();
  • const string testsql = @"SELECT Id FROM table ;"; var result = connection.Query(testsql).Select((p) => new { Id = p.Id });
  • 如果你真的是指通过 Select,那么它应该几乎可以像写的那样工作,特别是如果你转换属性以便它知道类型。我会在我得到一秒时测试它
  • 如果答案对我很重要,我会赞成这个问题,但这不是恕我直言。我想要没有动态中间的匿名类型。在我制作的一个小映射器上,我使用 connection.Query("SELECT * FROM Person").MapTo(() => new { Id = default(int), Name = default(string), Age = default(int?) }) 来声明匿名类型,我喜欢 Dapper 里面的东西 :)
  • 嗯,给出的答案是正确的,所以我不明白你不愿意投票。关于你的另一点,我完全同意。

标签: c# orm dapper


【解决方案1】:

Dapper 可以使用匿名类型吗?

当然看到非泛型查询覆盖,它返回一个动态的IDictionary&lt;string, object&gt; 这个对象是一个可以转换或使用点符号访问的扩展。

例如:

var v = connection.Query("select 1 as a, 2 as b").First(); 
Console.Write("{0} {1}",v.a, v.b) // prints: 1 2

然后可以做一个.Select

当然,你会得到一个IEnumerable&lt;dynamic&gt; ...你可以在上面运行任何你想要的东西。

【讨论】:

  • 所以你的意思是这个const string testsql = @"SELECT Id FROM table ;"; var result = connection.Query(testsql).ToList().Select((p) =&gt; new { Id = p.Id });应该可以工作?
  • @Peter 是的,虽然你可以更简洁一点:) connection.Query(testsql).Select((p) =&gt; new { (int)p.Id }); 如果你只选择 ID,你可以使用 connection.Query&lt;int&gt;(testsql).Select((Id) =&gt; new { Id });
  • 所以当我这样做时const string testsql = @"SELECT form_id as Id FROM form ;"; connection.Query(testsql).Select((p) =&gt; new { (int)p.Id }); 我得到编译时错误'无效的匿名类型成员声明器。必须使用成员分配、简单名称或成员访问来声明匿名类型成员。所以我试试这个var x = connection.Query&lt;dynamic&gt;(testsql).Select((p) =&gt; new { Id = (int)p.Id });,我得到运行时错误'System.Dynamic.DynamicObject'不包含'Id'的定义
  • @Peter 您正在选择form_id,因此您必须将其更改为:new { Id = (int)p.form_id })
【解决方案2】:

这是另一个使用 dapper 使用匿名类型的解决方案:

public static class DapperExtensions
{
    public static IEnumerable<T> Query<T>(this IDbConnection connection, Func<T> typeBuilder, string sql)
    {
        return connection.Query<T>(sql);
    }
}

并像这样使用它:

var data = connection.Query(() => new 
{
    ContactId = default(int),
    Name = default(string),
}, "SELECT ContactId, Name FROM Contact");

【讨论】:

  • 那么typeBuilder在扩展方法中即使没有用到它又有什么用呢?
  • 它通过 使用它
  • 不应该是“,T typebuilder,”吗?
  • 这很优雅。我不确定它是不是比当前接受的“更好”的答案,或者这只是个人品味的问题,但我会使用这个。
  • @BrunoSantos,不,有Func,T受返回类型干扰,有T,需要使用具体类型,即非匿名类型,所以T不行在这里(这将取代它)。
【解决方案3】:

只是对 Guillaume86 伟大解决方案的一个小改进:

public static IEnumerable<T> Query<T>(this IDbConnection connection, Func<T> typeBuilder,
    string sql, dynamic param = null, IDbTransaction transaction = null,
    bool buffered = true, int? commandTimeout = null, CommandType? commandType = null)
{
    return SqlMapper.Query<T>(connection, sql, param, transaction, buffered,
        commandTimeout, commandType);
}

【讨论】:

猜你喜欢
  • 2011-11-07
  • 2011-02-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多