C# 使用Dapper构建具有多对多关系的对象

C# 使用Dapper构建具有多对多关系的对象,c#,.net,object,relational-database,dapper,C#,.net,Object,Relational Database,Dapper,考虑一个Sqlite数据库,其部分模式如下所示(这里我们不考虑Book_标记表)。使用链接表media\u Tag,注意媒体项目和标签之间的多对多关系: 这些表的对象模型如下所示: public enum MediaType { Dvd, BluRay, Cd, Vhs, Vinyl, Other } public class MediaItem { public MediaType type { get; set; } pu

考虑一个Sqlite数据库,其部分模式如下所示(这里我们不考虑Book_标记表)。使用链接表
media\u Tag
,注意媒体项目和标签之间的多对多关系:

这些表的对象模型如下所示:

public enum MediaType
{
    Dvd,
    BluRay,
    Cd,
    Vhs,
    Vinyl,
    Other
}

public class MediaItem 
{
    public MediaType type { get; set; }
    public long number { get; set; } 
    public int runningTime { get; set; }
    public int releaseYear { get; set; }

    public ICollection<Tag> tags { get; set; }
}

public class Tag 
{
    public string name { get; set; }
}
public IEnumerable<MediaItem> readAll()
{
    using (var db = new SqliteConnection(this.connectionString))
    {
        db.Open();

        var sql = "SELECT * FROM Media;";
        return db.Query<MediaItem>(sql);
    }
}

public MediaItem readById(int id)
{
    using (var db = new SqliteConnection(this.connectionString))
    {
        db.Open();

        var sql = "SELECT * FROM Media WHERE id = @id;";
        var @params = new { id = id };
        return db.Query<MediaItem>(sql, @params).First();
    }
}
公共枚举媒体类型
{
数字化视频光盘
布鲁雷,
光盘
Vhs,
乙烯基,
其他
}
公共类MediaItem
{
公共媒体类型类型{get;set;}
公共长编号{get;set;}
公共int运行时{get;set;}
public int releaseYear{get;set;}
公共ICollection标记{get;set;}
}
公共类标签
{
公共字符串名称{get;set;}
}
目前,Dapper用于读取媒体表,但不考虑标签。代码如下:

public enum MediaType
{
    Dvd,
    BluRay,
    Cd,
    Vhs,
    Vinyl,
    Other
}

public class MediaItem 
{
    public MediaType type { get; set; }
    public long number { get; set; } 
    public int runningTime { get; set; }
    public int releaseYear { get; set; }

    public ICollection<Tag> tags { get; set; }
}

public class Tag 
{
    public string name { get; set; }
}
public IEnumerable<MediaItem> readAll()
{
    using (var db = new SqliteConnection(this.connectionString))
    {
        db.Open();

        var sql = "SELECT * FROM Media;";
        return db.Query<MediaItem>(sql);
    }
}

public MediaItem readById(int id)
{
    using (var db = new SqliteConnection(this.connectionString))
    {
        db.Open();

        var sql = "SELECT * FROM Media WHERE id = @id;";
        var @params = new { id = id };
        return db.Query<MediaItem>(sql, @params).First();
    }
}
public IEnumerable readAll()
{
使用(var db=new-SqliteConnection(this.connectionString))
{
db.Open();
var sql=“从媒体中选择*”;
返回db.Query(sql);
}
}
公共媒体项readById(int-id)
{
使用(var db=new-SqliteConnection(this.connectionString))
{
db.Open();
var sql=“从id=@id;”的介质中选择*;
var@params=new{id=id};
返回db.Query(sql,@params.First();
}
}

对于这两种情况(按id读取和从表中读取所有行),如何更改此项,以便在创建对象时考虑
mediateItem
标记
属性?是否需要联接查询?我相信Dapper有一种方法可以很好地做到这一点,但我不知道它是如何做到的。

您对链接表中的任何内容都不感兴趣,因此类似以下SQL的操作应该:

SELECT M.Id, M.title, M.type, M.Number, M.image, M.runningTime, M.releaseYear, T.Id, T.Name FROM Media as M 
INNER JOIN Media_Tag AS MT ON M.id = MT.mediaId
INNER JOIN Tags AS T ON T.id = MT.tagId
如果SqLite允许,您可以使用
M.*,T.*

我已冒昧地将Id属性添加到实体类中。我想你会需要它,否则你所有的标签都会不同,而不是唯一的。没有它,你可以让它工作,但它会让你的生活更轻松

公共类MediaItem
{
公共int-Id{get;set;}//New
公共媒体类型类型{get;set;}
公共长编号{get;set;}
公共int运行时{get;set;}
public int releaseYear{get;set;}
公共ICollection标记{get;set;}
}
公共类标签
{
公共int-Id{get;set;}//New
公共字符串名称{get;set;}
}
由于您的两个实体类都有一个唯一的id,因此您必须选择它们并确保它们在整个结果中是唯一的。我们通过使用字典来保存它们。我只是显示ReadAll,您应该能够相应地执行ReadById

stringsql=”“;
使用(var db=new-SqliteConnection(this.connectionString))
{            
var mediadctionary=新字典();
var tagDictionary=newdictionary();
var list=db.Query(
sql,
(媒体、标签)=>
{
媒体进入;
如果(!mediaDictionary.TryGetValue(media.Id,out mediaEntry))
{
//我以前没见过这个,我们把它加到字典里吧
媒体入口=媒体;
添加(mediateentry.Id,mediateentry);
}
标签输入;
if(!tagDictionary.TryGetValue(tag.Id,out tagEntry))
{
//我以前没见过这个,我们把它加到字典里吧
tagEntry=tag;
tagDictionary.Add(tagEntry.Id,tagEntry);
}
//将标记添加到集合中
mediateentry.Tags.Add(tagEntry);
返回媒体条目;
},
splitOn:“Id”)//这是默认值,可以省略
.Distinct()
.ToList();