【问题标题】:Making Linq To SQL DRY使 Linq To SQL DRY
【发布时间】:2010-10-27 02:34:04
【问题描述】:

我们决定在我们最近的项目中使用 Linq To SQL 作为我们的数据层。我们有一个功能性的解决方案,到目前为止,它已经处理了我们提出的所有问题,但有一个主要问题。我们必须一遍又一遍地编写相同的方法来从我们的数据库中检索略有不同的结果集。

举个例子:

        public List<TeamBE> GetTeamsBySolutionID(Guid SolutionID)
        {
            List<TeamBE> teams = new List<TeamBE>();

            Esadmin db = new Esadmin(_connectionString);

            var qry = (from teamsTable in db.Teams
                       join solutionsTable in db.Solutions on teamsTable.SolutionID equals solutionsTable.SolutionID
                       where teamsTable.SolutionID == SolutionID
                       select new { teamsTable, solutionsTable.SolutionName });

            foreach (var result in qry)
            {
                TeamBE team = new TeamBE();

                team.TeamID = result.teamsTable.TeamID;
                team.Description = result.teamsTable.Description;
                team.Status = result.teamsTable.Status;
                team.LastModified = result.teamsTable.LastModified;
                team.SolutionID = result.teamsTable.SolutionID;
                team.SolutionName = result.SolutionName;
                team.Name = result.teamsTable.Name;
                team.LocationLevel = result.teamsTable.LocationLevel;
                team.AORDriven = result.teamsTable.AoRDriven;
                team.CriteriaID = result.teamsTable.CriteriaID ?? Guid.Empty;

                teams.Add(team);
            }
            return teams;
        }

        public TeamBE GetTeamByID(Guid TeamID)
        {
            Esadmin db = new Esadmin(_connectionString);
            TeamBE team = new TeamBE();

            var qry = (from teamsTable in db.Teams
                       join solutionsTable in db.Solutions on teamsTable.SolutionID equals solutionsTable.SolutionID
                       where teamsTable.TeamID == TeamID
                       select new { teamsTable, solutionsTable.SolutionName }).Single();

            team.TeamID = qry.teamsTable.TeamID;
            team.Description = qry.teamsTable.Description;
            team.Status = qry.teamsTable.Status;
            team.LastModified = qry.teamsTable.LastModified;
            team.SolutionID = qry.teamsTable.SolutionID;
            team.SolutionName = qry.SolutionName;
            team.Name = qry.teamsTable.Name;
            team.LocationLevel = qry.teamsTable.LocationLevel;
            team.AORDriven = qry.teamsTable.AoRDriven;
            team.CriteriaID = qry.teamsTable.CriteriaID ?? Guid.Empty;

            return team;
        }

不断地令人作呕。

有没有办法将 Linq 结果作为参数传递给函数,这样我就可以将我的对象映射放在一个函数中,而不会重复太多?

【问题讨论】:

    标签: c# .net linq linq-to-sql .net-3.5


    【解决方案1】:

    我快速尝试了一下。可能无法编译(尤其是团队中的“来自 teamsTalbe”),但想法是您可以分解出返回 IQueryable 的内容。尽管您是 IQueryable 返回匿名类型,但这是行不通的。所以您可以需要创建一个显式类型来代替“select new { teamsTable, solutionsTable.SolutionName }”

        public List<TeamBE> GetTeamsBySolutionID(int solutionID)
        {
            Esadmin db = new Esadmin(_connectionString);
            return GetTeamsBy(db, _GetTeamsBySolutionID(db, solutionID));
        }
    
        IQueryable<Team> _GetTeamsBySolutionID(Esadmin db, int solutionID)
        {
            return from teamsTable in db.Teams
                   where teamsTable.SolutionID == SolutionID
                   select teamsTable;
        }
    
        List<TeamBE> GetTeamsBy(Esadmin db, IQueryable<Team> teams)
        {
            List<TeamBE> teams = new List<TeamBE>();
    
            var qry = (from teamsTable in teams
                       join solutionsTable in db.Solutions on teamsTable.SolutionID equals solutionsTable.SolutionID
                       select new { teamsTable, solutionsTable.SolutionName });
    
            foreach (var result in qry)
            {
                TeamBE team = new TeamBE();
    
                team.TeamID = result.teamsTable.TeamID;
                team.Description = result.teamsTable.Description;
                team.Status = result.teamsTable.Status;
                team.LastModified = result.teamsTable.LastModified;
                team.SolutionID = result.teamsTable.SolutionID;
                team.SolutionName = result.SolutionName;
                team.Name = result.teamsTable.Name;
                team.LocationLevel = result.teamsTable.LocationLevel;
                team.AORDriven = result.teamsTable.AoRDriven;
                team.CriteriaID = result.teamsTable.CriteriaID ?? Guid.Empty;
    
                teams.Add(team);
            }
            return teams;
        }
    

    【讨论】:

    • 这正是我想要做的,但是当 SQL Metal 没有生成与之匹配的任何内容时,如何创建该显式类型。
    • 只需为您拥有的两个部分创建一个具有公共属性的类。创建对象时,使用带有属性初始值设定项的默认构造函数(不要将属性作为构造函数参数,否则表达式无法映射到 IQueryable)
    • 我想看看这个实际操作,你知道关于这类事情的任何资源或教程吗?
    • 任何好的LINQ书,注意关于延迟执行的部分(了解如何使用IQueryable vs IEnumerable)
    【解决方案2】:

    我认为您可以将 qry 变量声明为 IEnumerable&lt;YourDataTypeEntity&gt; 并将其传递给方法。我倾向于喜欢将其作为构造函数:

    class MyDataType
    {
      public MyDataType() {}
      public MyDataType(MyDataTypeEntity mdte)
      {
        // set properties and fields here
      }
    
      // ...
    }
    

    【讨论】:

    • 这是很好的信息,当我从单个表或存储过程中提取时,它会起作用。但请注意,我在我的 linq 语句中进行了联接,因此我准备好将 SolutionName 值放入我的对象中。我会使用什么类型。
    • 我遇到过一些关于这个问题的简单案例,我通常通过在数据库中实现一个视图来解决这个问题。
    【解决方案3】:

    您可以传递一个 IQueryable,然后当您想要处理结果时,您可以迭代结果。我不确定这是否是您要问的那种事情,或者我是否对您的问题有意见。

    【讨论】:

      【解决方案4】:

      还可以查看AutoMapper,这是一个 API,它使用基于约定的匹配算法来匹配对象中的源值和目标值。使用它可能会删除您的大部分 a = b.c 代码。

      【讨论】:

      • 感谢您的提示。我将不得不在路上的一个项目上试一试,谢谢。
      【解决方案5】:

      我用 entityFramework 实现了这样的东西:

      //This returns an IQueryable of your Linq2Sql entities, here you put your query.
      protected IQueryable<Team> GetTeamByIdQuery(Guid teamID)
      {
          var qry = (from TeamsTable in db.Teams
                     where blablabla.....
                     select Teams;
      
          return qry;
      }
      
      
      //This will return your real entity
      public IList<TeamBE> GetTeamById(Guid teamID)
      {
          var query = this.GetTeamByIdQuery(teamID);
          IList<TeamBE> teams = ExecuteTeamQuery(query).toList<TeamBE>();
      
          return teams;
      }
      
      
      //this method will do the mapping from your L2S entities to your model entities
      protected IQueryable<TeamBE> ExcuteTeamQuery(IQueryable<Team> query)
      {
          return 
              query.select<Team, TeamBE> (team => 
                 new TeamBE
                 {
                    TeamID = team.TeamID,
                    Description = team.Description 
                 }
      
      }
      

      还没有测试这么多,但它有效。我还在努力根据 bitflag 参数定义要加载的属性。我还没有让它工作,但会是这样的:

      public IQueryable<TeamBE> ExcuteTeamQuery(IQueryable<Team> query, int loadLevel)
      {
          return 
              query.select<Team, TeamBE> (team => 
                 new TeamBE
                 {
                    TeamID = team.TeamID,
                    TeamMembers = (HaveToLoad(LoadLevel.TeamMembers, loadLevel)) ? team.TeamMembers : null 
                 }
      
      }
      
      
      enter code here
      

      【讨论】:

        【解决方案6】:

        尝试扩展方法: 如果你有

        public IQueryable<Team> GetTeams() { return db.Teams; }
        

        尝试写作:

        public IQueryable<Team> WithDivisionId(this IQueryable<Team> qry, int divisionId)
        { return (from t in qry where t.DivisionId = divisionId select t);}
        

        这样你就可以编写多个扩展方法来查询任何IQueryable&lt;Team&gt; 并将它们分层...

        要让第 1 赛区的球队在某个时候获得 9 场或更多胜且连续 5 场或更多,您只需编写:

        GetTeams().WithDivisionId(1).HavingWonAtLeast(9).WithWinningStreak(5);
        

        【讨论】:

        • 如果您不知道,Linq 将根据所有过滤器生成适当的 SQL 语句并创建将执行的“最终”查询 - 它不会触发每个查询功能。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-12-09
        相关资源
        最近更新 更多