简体   繁体   English

如何在C#linq asp.net MVC中使用逗号分隔值列连接两个表

[英]how to join two tables with comma separated values column in c# linq asp.net mvc

I have two tables Profile and CourseList . 我有两个表ProfileCourseList

Profile table: Profile表:

ID   | Name   | CourseId
-----+--------+----------
 1   | Zishan |  1,2                                          
 2   | Ellen  |  2,3,4 

CourseList table: CourseList表:

courseid | coursename 
---------+--------------
   1     |  java
   2     |  C++
   3     |  oracle
   4     |  dot net

Here I am joining the two tables and get results and that result in my View page for particular ID like... 在这里,我将两个表连接起来并得到结果,然后结果在“查看”页面中显示特定的ID,例如...

If I call ID = 1 in my view: 如果我认为ID = 1:

Name: Zishan, 姓名:紫山

course name: java,C++ 课程名称:java,C ++

If if i call ID = 2 in my view: 如果我认为ID = 2:

Name: Ellen, 姓名:艾伦(Ellen)

course name: java,C++,oracle. 课程名称:java,C ++,oracle。

So I write this Linq query in my controller: 因此,我在控制器中编写了此Linq查询:

var account = db.Profile.Where(x => x.PId == pid).FirstOrDefault();

string  CourseIDS = string.Join(",",account.CourceId);

var courselist = (from p in db.profile
                  join co in db.CourceList on p.CourceId equals co.courseId 
                  .ToString()  into co1 from co2 in co1.Where(x => 
                   LanguageIDS.Contains(x.courseId.ToString()))
            select new ViewProfileVM
            {
               courseName = string.Join(",", co2.courseName)
            }).FirstOrDefault();

ViewBag.courselist = courselist;

Then I pass ViewBag to view and show results..... 然后,我通过ViewBag查看并显示结果。

Please help me the linq query is not working and in future i want to add join LanguagesList and CountryList like same as CourceList so please suggest me a simple solution for this issue.. 请帮助我linq查询无法正常工作,将来我想像加入CourceList一样添加join LanguagesList和CountryList,所以请为我建议一个简单的解决方案。

Thanks, 谢谢,

I would second what John M has commented, comma separated values is not a recommended approach in relational Database. 我要说一下John M的评论,在关系数据库中不建议使用逗号分隔的值。 But since you have it, you could use following to get your expected result. 但是,既然有了它,就可以使用以下方法获得预期的结果。

var profileList = profiles.SelectMany(x=> x.CourseId.Split(',')
                        .Select(c=> 
                        new 
                        {
                            Name= x.Name, 
                            CourseId = int.Parse(c) 
                        }));
var result = profileList.Join(courses,
                p=>p.CourseId,
                c=>c.Id,
                (p,c)=>new {Name = p.Name, Courses= c.CourseName})
                .GroupBy(x=>x.Name)
                .Select(x=>new 
                {
                Name = x.Key, 
                Courses = string.Join(",",x.ToList().Select(k=>k.Courses))
                });

Where profiles and courses are collection of representiatives classes of your data structures. 配置文件和课程是数据结构的代表类的集合。

public class Profile
{
public int Id{get;set;}
public string Name{get;set;}
public string CourseId{get;set;}
}


public class Coursename
{
public int Id{get;set;}
public string CourseName{get;set;}
}

This would give you expected output as 这将为您提供预期的输出

Name : Zishan Courses : Java,C++ 姓名:紫山课程:Java,C ++

Name:Ellen Courses:C++,Oracle,Dot Net 名称:艾伦课程:C ++,Oracle,Dot Net

Following is the sample data i used for testing. 以下是我用于测试的样本数据。

var profiles = new Profile[]
                {
                    new Profile{Id = 1, Name = "Zishan", CourseId = "1,2"},
                    new Profile{Id = 2, Name = "Ellen", CourseId = "2,3,4"}
                };
var courses = new Coursename[]
                {
                    new Coursename{Id=1, CourseName = "Java"},
                    new Coursename{Id=2, CourseName = "C++"},
                    new Coursename{Id=3, CourseName = "Oracle"},
                    new Coursename {Id=4, CourseName = "Dot Net"}
                };

Hope that helps 希望能有所帮助

It seems that every Profile has zero or more Courses , and every Course belongs to zero or more Profiles : a straightforward many-to-many relationship. 似乎每个Profile都有零个或多个Courses ,每个Course属于零个或多个Profiles :直接的多对多关系。

Normally in a relational database, this would be implemented using a junction table: a separate table, with two columns that act as foreign keys: ProfileId and CourseId. 通常在关系数据库中,这将使用联结表(一个单独的表,具有充当外键的两列)来实现:ProfileId和CourseId。 In your example: 在您的示例中:

  • For Zishan, who has Id 1 we would have [1, 1] and [1, 2], indicating that Zishan attends Courses with Id 1 and 2; 对于拥有ID 1的资山,我们将有[1、1]和[1、2],这表明资山以ID 1和2参加课程;
  • For Ellen with Id = 2, we would have [2, 2] [2, 3] [2,4]. 对于ID = 2的Ellen,我们将有[2,2] [2,3] [2,4]。

Alas, your database designer chose not to follow this standard database pattern. las,您的数据库设计者选择不遵循此标准数据库模式。 And you are stuck with the problems. 而且您陷入困境。

The best solution depends a bit on how long you will be stuck with this database, how often it will change, how often you will ask for "Profiles with their Courses" and "Courses with their attendants". 最好的解决方案取决于您在此数据库上待了多长时间,更改的频率,询问“课程的个人资料”和“与之相关的课程”的频率。

Best Solution: add a junction table to the database 最佳解决方案:将联结表添加到数据库

The best solution would be a one-time migration of your database: create the junction table and add the [profile.Id, Course.Id] combinations to this list. 最好的解决方案是一次性迁移数据库:创建联结表,并将[profile.Id, Course.Id]组合添加到此列表中。 After that remove the CourseId column. 之后,删除CourseId列。

class ProfileCourse
{
    public int ProfileId {get; set;}
    public int CourseId {get; set;}
}

var ProfileIdCourseIdCombinations = db.Profiles
    .SelectMany(profile => profile.CourseIds.Split(',", StringSplitOptions.RemoveEmptyEntries),

    (profile, splitCourseId) => new ProfileCourse
    {
         ProfileId = profile.Id,
         CourseId = splitCourseId,
    });

This has to be done only once. 只需执行一次。 Similar queries in future will be fairly standard. 将来类似的查询将是相当标准的。 Everyone who is a fluent LINQer, will know how to implement the queries. 精通LINQer的每个人都将知道如何实现查询。 Disadvantage: the database change. 缺点:数据库更改。

Sub-optimal solution: mimic the junction table 次优解决方案:模拟联结表

Quite often people have an intermediate (adapter) layer between the use cases and the actual database. 人们经常在用例和实际数据库之间有一个中间(适配器)层。 This way you can change the database without having to change the users, or vice versa. 这样,您无需更改用户即可更改数据库,反之亦然。 The pattern for this adapter layer is quite often called the repository pattern. 此适配器层的模式通常称为存储库模式。

The Idea is that you create a Repository class that exposes your tables as IEnumerable sequence of items. 想法是您创建一个Repository类,该类将表显示为IEnumerable项目序列。 The junction table will not be a real table, it will be created whenever it is asked for. 联结表将不是一个真正的表,它将在需要时创建。

class Repository
{
    public Respository(MyDbContext db)
    {
        this.db = db;
    }
    private readonly MyDbContext db;
    private IReadonlyCollection<ProfileCourse> profilesCourses = null;

    public IEnumerable<Profile> Profiles => this.db.Profiles;
    public IEnumerable<Course> Courses => this.db.Courses;

    public IEnumerable<ProfileCourse> ProfilesCourses
    {
         get
         {
             if (this.profilesCourses == null
             {
                 this.profilesCourses = ... // the SelectMany from above
                     .ToList();
             }
             return this.profilesCourses;
         }
    }
}

This way your junction table will be created only once per time you create your Repository. 这样,每次创建存储库时,将只创建一次联结表。 It will only be created when used. 仅在使用时创建。

This solution is sub-optimal, because the junction table needs to be recreated every time you'll use it in a new Repository. 该解决方案不是最优的,因为每次在新的存储库中使用联结表时都需要重新创建联结表。 Furthermore, you can't add Profiles nor Courses using this Repository class. 此外,您不能使用此存储库类添加“个人资料”或“课程”。 If will be quite some work to create functions to Add / Remove profiles and courses to your Repository. 如果要创建一些功能来添加/删除个人档案和课程到您的存储库,将会花费很多精力。 It is possibly easier to recreate the repository. 重新创建存储库可能更容易。

You'll get your answer by asking the repository instead of your db 您将通过询问存储库而不是数据库来获得答案

var repository = new Repository(db);
var profilesWithTheirCourses = repository.Profiles.GroupJoin(repository.ProfilesCourses,

    profile => profile.Id,                       // from every profile take the Id
    profileCourse => profileCourse.ProfileId,    // from every profileCourse take the ProfileId,

    (profile, profileCourses) => new     // take every profile with all its matching
    {                                    // profileCourses, to make a new obhect
        // Profile properties; add only those you plan to use:
        Id = profile.Id,
        Name = profile.Name,

        Courses = profileCourses.Join(repository.Courses, // join profileCourse with courses
           profileCourse => profileCourse.CourseId,       // from profileCourse take CourseId
           course => course.Id,                            // from course take Id
           (profileCourse, course) => new                  // when they match make a new
           {   // again: only the properties you actually plan to use
               Id = course.Id,
               Name = course.Name,
           })
           .ToList(),
    });

Solution for this problem only 仅解决此问题

If you decide to make a solution for this problem only, you can combine the SelectMany and the Join into one big LINQ statement. 如果您决定仅解决此问题,则可以将SelectManyJoin成一个大的LINQ语句。

Advantage: quick solution; 优点:快速解决方案; Disadvantage: difficult to read, to test, and to maintain. 缺点:难以阅读,测试和维护。 Similar problems in future will have a similar sub-optimal solution, 将来类似的问题也会有类似的次优解决方案,

var profilesWithTheirCourses = db.Profiles.SelectMany(
    profile => profile.CourseIds.Split(',", StringSplitOptions.RemoveEmptyEntries),
    (profile, splitCourseIds) => new
    {
        Id = profile.Id,
        Name = profile.Name,

        Courses = splitCourseIds.Join(db.Courses,
           courseId => courseId,
           course => course.Id,
           (courseId, course) => new
           {
               Id = course.Id,
               Name = course.Name,
           })
           .ToList(),
    });

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何使用 c# asp.net 从具有逗号分隔值的列的表中获取记录? - How to fetch records from table having column with comma separated values using c# asp.net? MVC-如何使用 Linq ASP.NET MVC 连接两个表或模型? - MVC-How to Join Two Tables or Models using Linq ASP.NET MVC? 在 ASP.NET MVC C# 中连接到多个表或连接两个表 - Connect to multiple tables or join two tables in ASP.NET MVC C# 如何在asp.net中显示带有两个具有相同列名但具有不同值的表的图表C# - how to show chart in asp.net with two tables with same column names but with different values in it C# 如何在Linq中加入具有逗号分隔值的列 - How to Join with a column having Comma Separated Values in Linq 我如何在ASP.NET MVC中使用Linq,C#从联接表中访问列 - How do I access columns from joined tables using Linq, C# in asp.net MVC 如何在 Linq &lt;&gt; ASP.NET MVC &lt;&gt; C# 中使用“IN”语句 - How to utilize “IN” statement with Linq <> ASP.NET MVC <> C# 如何使用LINQ SQL连接基于ID连接3个表? C#MVC(.NET Core 2.0) - How to join 3 tables based on ID using LINQ SQL join? C# MVC (.NET Core 2.0) 在ASP.NET MVC中连接两个表的正确方法是什么? - What is the proper way to Join two tables in ASP.NET MVC? 如何在C#的datagridview列中添加逗号分隔的值 - how to add values with separated comma in datagridview column in c#
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM