【问题标题】:ServiceStack Ormlite Join WrapperServiceStack Ormlite Join Wrapper
【发布时间】:2014-06-20 23:37:01
【问题描述】:

我在我的数据访问中为 OrmLite 中的联接创建了一个包装器。

我现在遇到了异常:

System.Exception : 表达式应该只有一列

我所有的实体都有一个 BaseEntity 基类。 JoinType 只是一个包含列、选择和连接位置的外观。

我的包装如下:

public IEnumerable<TResultEntity> Join<TResultEntity>(IList<JoinType<BaseEntity, BaseEntity>> joins)
        {
            var result = new List<TResultEntity>();

            if (joins != null && joins.Any())
            {
                var joinBuilder = new JoinSqlBuilder<T, BaseEntity>();

                foreach (var join in joins)
                {
                    joinBuilder = joinBuilder.Join(join.LeftColumn, join.RightColumn, join.LeftSelection, join.RightSelection, join.LeftWhere, join.RightWhere);
                }

                var connection = this.DataConnection;
                using (connection)
                {
                    var joinSql = joinBuilder.SelectDistinct().ToSql();
                    result = connection.SqlList<TResultEntity>(joinSql);
                }
            }

            return result;
        }

做同样的事情,没有列表似乎工作:

public IEnumerable<TResultEntity> Join<TLeftTable1, TRightTable1, TLeftTable2, TRightTable2, TResultEntity>(
            JoinType<TLeftTable1, TRightTable1> join1,
            JoinType<TLeftTable2, TRightTable2> join2) 
            where TLeftTable1 : BaseEntity 
            where TRightTable1 : BaseEntity 
            where TLeftTable2 : BaseEntity 
            where TRightTable2 : BaseEntity

编辑 - 我正在使用以下调用进行测试:

// Act
                var join1 = new JoinType<AnswerEntity, UserSurveyStateEntity>(
                l => l.OwnerId,
                r => r.UserId,
                x => new { UserId = x.OwnerId, x.QuestionId, AnswerId = x.Id, x.AnswerValue });

                var join2 = new JoinType<SurveyEntity, UserSurveyStateEntity>(
                l => l.Id,
                r => r.SurveyInstanceId,
                x => new { SurveyId = x.Id, SurveyName = x.Name, x.StatusValue },
                null,
                null,
                x => x.StatusValue == (int)UserSurveyStatus.Complete);

                var joins = new List<JoinType<BaseEntity, BaseEntity>>();
                joins.Add(join1.As<JoinType<BaseEntity, BaseEntity>>());
                joins.Add(join2.As<JoinType<BaseEntity, BaseEntity>>());

                var result = dataAccess.Join<AnswerEntity>(joins).ToList();

【问题讨论】:

  • 它在哪条线上爆炸?
  • @wbennett joinBuilder = joinBuilder.Join(join.LeftColumn, join.RightColumn, join.LeftSelection, join.RightSelection, join.LeftWhere, join.RightWhere);
  • 什么ormlite方言提供者?
  • 你能提供一个如何使用它的测试示例吗?
  • 感谢@wbennett - 我已更新问题以提供引发错误的实际测试代码。

标签: c#-4.0 generics ormlite-servicestack


【解决方案1】:

编辑 - 现在看到用例,错误与转换为基本类型和构建器为具体 BaseEntity 存储多个列选择器有关。考虑添加一个抽象 JoinType 类,并修改 JoinType 类,以便它为构建器应用连接。

例如:

    public class Entity
    {
        public string Id { get; set; }
    }
    public class Foo
        : Entity
    {
        public string Value { get; set; }
    }

    public class Bar
        : Entity
    {
        public string FooId { get; set; }
        public string Value { get; set; }
    }

    public abstract class JoinType
    {
        public abstract JoinSqlBuilder<TNew, TBase> ApplyJoin<TNew, TBase>(
            JoinSqlBuilder<TNew, TBase> bldr);
    }

    public class JoinType<TSource, TTarget>
        : JoinType
    {
        private Expression<Func<TSource, object>> _sourceColumn;
        private Expression<Func<TTarget, object>> _destinationColumn;
        private Expression<Func<TSource, object>> _sourceTableColumnSelection;
        private Expression<Func<TTarget, object>> _destinationTableColumnSelection;
        private Expression<Func<TSource, bool>> _sourceWhere;
        private Expression<Func<TTarget, bool>> _destinationWhere;

        public JoinType(Expression<Func<TSource, object>> sourceColumn,
            Expression<Func<TTarget, object>> destinationColumn,
            Expression<Func<TSource, object>>
                sourceTableColumnSelection = null,
            Expression<Func<TTarget, object>>
                destinationTableColumnSelection = null,
            Expression<Func<TSource, bool>> sourceWhere = null,
            Expression<Func<TTarget, bool>> destinationWhere =
                null)
        {
            this._sourceColumn = sourceColumn;
            this._destinationColumn = destinationColumn;
            this._sourceTableColumnSelection = sourceTableColumnSelection;
            this._destinationTableColumnSelection =
                destinationTableColumnSelection;
            this._sourceWhere = sourceWhere;
            this._destinationWhere = destinationWhere;
        }

        public override JoinSqlBuilder<TNew, TBase> ApplyJoin<TNew, TBase>(
            JoinSqlBuilder<TNew, TBase> bldr)
        {
            bldr.Join(_sourceColumn,
                _destinationColumn,
                _sourceTableColumnSelection,
                _destinationTableColumnSelection,
                _sourceWhere,
                _destinationWhere);

            return bldr;
        }
    }

    public class FooBar
    {
        [References(typeof(Foo))]
        public string FooId { get; set; }
        [References(typeof(Bar))]
        public string BarId { get; set; }
        [References(typeof(Foo))]
        public string FooValue { get; set; }
        [References(typeof(Bar))]
        public string BarValue { get; set; }
    }

    /*
    This join accomplishes the same thing, but just returns the SQL as a string.
    */
    public string Join<TResultEntity,TBase>(IList<JoinType>joins)
    {
        var result = new List<TResultEntity>();

        if (joins != null && joins.Any())
        {
            var joinBuilder = new JoinSqlBuilder<TResultEntity, TBase>();

            foreach (var joinType in joins)
            {
                //call the apply join, and the join type will know the valid types
                joinBuilder = joinType.ApplyJoin(joinBuilder);
            }

            return joinBuilder.SelectDistinct().ToSql();
        }

        return null;
    }

    [TestMethod]
    public void TestMethod1()
    {
        OrmLiteConfig.DialectProvider = SqlServerDialect.Provider;

        var joins = new List<JoinType>();

        var jointype1 = new JoinType<Bar, FooBar>(
            bar => bar.Id,
            bar => bar.BarId,
            bar => new { BarId = bar.Id, BarValue = bar.Value }
            );
        joins.Add(jointype1);
        var joinType2 = new JoinType<Foo, FooBar>(
            foo => foo.Id,
            bar => bar.FooId,
            foo => new { FooId = foo.Id, FooValue = foo.Value}
            );
        joins.Add(joinType2);

        var str = Join<FooBar, Bar>(joins);
    }

旧答案 - 仍然与错误相关

此错误是由您的选择器join.LeftColumn 或您的join.RightColumn 包含两个选择器引起的。确保它们只包含一个。

我能够通过以下测试重现错误:

    public class Entity
    {
        public string Id { get; set; }
    }
    public class Foo
        : Entity
    {
        public string Value { get; set; }
    }

    public class Bar
        : Entity
    {
        public string FooId { get; set; }
        public string Value { get; set; }
    }

    public class FooBar
    {
        [References(typeof(Foo))]
        public string FooId { get; set; }
        [References(typeof(Bar))]
        public string BarId { get; set; }
        [References(typeof(Foo))]
        public string FooValue { get; set; }
        [References(typeof(Bar))]
        public string BarValue { get; set; }
    }

    [TestMethod]
    public void TestMethod1()
    {
        OrmLiteConfig.DialectProvider = SqlServerDialect.Provider;
        var bldr = new JoinSqlBuilder<FooBar,Bar>();
        bldr = bldr.Join<FooBar, Bar>(
            bar => bar.BarId, 
            bar => new { Id1 = bar.Id, Id2 = bar.Id},//<-- this should only contain a single member
            bar => new { BarId =bar.BarId },
            bar => new { BarId = bar.Id, BarValue = bar.Value},
            bar => bar.BarId != null,
            bar => bar.Id != null
            );

        var str = bldr.SelectDistinct().ToSql();
    }

【讨论】:

  • 这适用于具有相同源和目标的连接列表。如果我有不同的目标和来源,它将无法工作。例如 - UserEntity + QuestionEntity & QuestionEntity + AnswerEntity。
  • 好的。请参阅我修改后的答案,了解您为什么会遇到该异常。确保前两个参数不包含多个成员表达式。
  • 我认为这是因为我以某种方式将我的实体转换回基类。
  • 我已经用适合我的解决方案更新了答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-01-19
  • 2022-01-18
  • 2021-11-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多