C# 简洁的一对多关系
我有3个表,结构如下:C# 简洁的一对多关系,c#,asp.net-mvc,asp.net-core,asp.net-core-mvc,dapper,C#,Asp.net Mvc,Asp.net Core,Asp.net Core Mvc,Dapper,我有3个表,结构如下: CREATE TABLE [User]( Id int NOT NULL, Name varchar(50) PRIMARY KEY (Id) ) CREATE TABLE [Role]( Id int NOT NULL, UserId int NOT NULL, Name varchar(50), PRIMARY KEY (Id), FOREIGN KEY (UserId) REFERENCES [Use
CREATE TABLE [User](
Id int NOT NULL,
Name varchar(50)
PRIMARY KEY (Id)
)
CREATE TABLE [Role](
Id int NOT NULL,
UserId int NOT NULL,
Name varchar(50),
PRIMARY KEY (Id),
FOREIGN KEY (UserId) REFERENCES [User](Id)
)
CREATE TABLE [Description](
Id int NOT NULL,
RoleId int NOT NULL,
Name varchar(50)
FOREIGN KEY (RoleId) REFERENCES [Role](Id)
)
正如您所看到的,它是嵌套两次的一对多关系。在代码中,我有以下类来表示它们:
public class User
{
public int Id { get; set; }
public string Name { get; set; }
public IEnumerable<Role> Roles { get; set; }
}
public class Role
{
public int Id { get; set; }
public int UserId { get; set; }
public string Name { get; set; }
public IEnumerable<Description> Descriptions { get; set; }
}
public class Description
{
public int Id { get; set; }
public int RoleId { get; set; }
public string Name { get; set; }
}
然后我像这样处理它:
var queryFour = "SELECT u.Id as 'UserId', u.Name as 'UserName', r.Id as 'RoleId', r.Name as 'RoleName', d.Id as 'DescriptionId', d.Name as 'DescriptionName' FROM [User] u INNER JOIN [Role] r ON u.Id = r.UserId INNER JOIN [Description] d ON r.Id = d.RoleId WHERE u.Id = 1";
var conn = new SqlConnection();
using (var con = conn)
{
var myUser = new User();
var result = con.Query<Combination>(queryFour);
if (result != null)
{
var user = result.FirstOrDefault();
myUser.Id = user.UserId;
myUser.Name = user.UserName;
var roles = result.GroupBy(x => x.RoleId).Select(x => x.FirstOrDefault());
var myRoles = new List<Role>();
if (roles != null)
{
foreach (var role in roles)
{
var myRole = new Role
{
Id = role.RoleId,
Name = role.RoleName
};
var descriptions = result.Where(x => x.RoleId == myRole.Id);
var descList = new List<Description>();
foreach (var description in descriptions)
{
var desc = new Description
{
Id = description.DescriptionId,
RoleId = description.RoleId,
Name = description.DescriptionName
};
descList.Add(desc);
}
myRole.Descriptions = descList;
myRoles.Add(myRole);
}
}
myUser.Roles = myRoles;
}
Console.WriteLine("User: " + myUser.Name);
foreach (var myUserRole in myUser.Roles)
{
Console.WriteLine("Role: " + myUserRole.Name);
foreach (var description in myUserRole.Descriptions)
{
Console.WriteLine("Description: " + description.Name);
}
}
}
public static void Main(String[] args)
{
int roleID = 6;
UserDataAccess dataAccess = new UserDataAccess();
IEnumerable<User> usersInRole = dataAccess.GetUsersByRoleID(roleID);
DisplayManager displayManager = new DisplayManager(usersInRole);
displayManager.DisplayInfo();
}
var queryFour=“选择u.Id作为‘UserId’,u.Name作为‘UserName’,r.Id作为‘RoleId’,r.Name作为‘RoleName’,d.Id作为‘DescriptionId’,d.Name作为‘DescriptionName’,从[User]u内部联接[Role]r上选择u.Id=r.UserId内部联接[Description]d上选择r.Id=d.RoleId,其中u.Id=1”;
var conn=new SqlConnection();
使用(var con=conn)
{
var myUser=新用户();
var result=con.Query(queryFour);
如果(结果!=null)
{
var user=result.FirstOrDefault();
myUser.Id=user.UserId;
myUser.Name=user.UserName;
var roles=result.GroupBy(x=>x.RoleId);
var myRoles=新列表();
if(角色!=null)
{
foreach(角色中的var角色)
{
var myRole=新角色
{
Id=role.RoleId,
Name=role.RoleName
};
var descriptions=result.Where(x=>x.RoleId==myRole.Id);
var descList=新列表();
foreach(描述中的变量描述)
{
var desc=新描述
{
Id=description.DescriptionId,
RoleId=description.RoleId,
Name=description.DescriptionName
};
描述列表。添加(描述);
}
myRole.Descriptions=descList;
添加(myRole);
}
}
myUser.Roles=myRoles;
}
Console.WriteLine(“用户:+myUser.Name”);
foreach(myUser.Roles中的var myUserRole)
{
Console.WriteLine(“角色:+myUserRole.Name”);
foreach(myUserRole.Descriptions中的变量描述)
{
Console.WriteLine(“Description:+Description.Name”);
}
}
}
两个方法中的结果输出相同,第二个方法使用1个查询,而不是3个查询
编辑2:需要考虑的是,我对这3个表的数据经常更新。
编辑3:private static void SqlTest()
{
using (IDbConnection connection = new SqlConnection())
{
var queryOne = "SELECT Id FROM [TestTable] With(nolock) WHERE Id = 1";
var queryTwo = "SELECT B.Id, B.TestTableId FROM [TestTable] A With(nolock) INNER JOIN [TestTable2] B With(nolock) ON A.Id = B.TestTableId WHERE A.Id = 1";
var queryThree = "SELECT C.Id, C.TestTable2Id FROM [TestTable3] C With(nolock) INNER JOIN [TestTable2] B With(nolock) ON B.Id = C.TestTable2Id INNER JOIN [TestTable] A With(nolock) ON A.Id = B.TestTableId WHERE A.Id = 1";
var gridReader = connection.QueryMultiple(queryOne + " " + queryTwo + " " + queryThree);
var user = gridReader.Read<Class1>().FirstOrDefault();
var roles = gridReader.Read<Class2>().ToList();
var descriptions = gridReader.Read<Class3>().ToLookup(d => d.Id);
user.Roles= roles;
user.Roles.ForEach(r => r.Properties = descriptions[r.Id].ToList());
}
}
private static void SqlTest()
{
使用(IDbConnection connection=newSQLConnection())
{
var queryOne=“使用(nolock)从[TestTable]中选择Id,其中Id=1”;
var queryTwo=“从[TestTable]A中选择B.Id,B.TestTableId,并在A.Id=B.TestTableId中使用(nolock)内部连接[TestTable2]B和(nolock)”,其中A.Id=1”;
var querytree=“从[TestTable3]C中选择C.Id,C.TestTable2Id,并在B上使用(nolock)内部连接[TestTable2]B和(nolock)。Id=C.TestTable2Id内部连接[TestTable]A和(nolock)在A.Id=B.TestTableId,其中A.Id=1”;
var gridReader=connection.QueryMultiple(queryOne+“”+queryTwo+“”+queryTree);
var user=gridReader.Read().FirstOrDefault();
var roles=gridReader.Read().ToList();
var descriptions=gridReader.Read().ToLookup(d=>d.Id);
user.Roles=角色;
user.Roles.ForEach(r=>r.Properties=descriptions[r.Id].ToList());
}
}
另一种方法(使用.Net核心处理代码片段):
public List<Combination> GetData(int userId)
{
String query = "select * from myview" + " where userId = " + userId + ";";
using (System.Data.Common.DbConnection _Connection = database.Connection)
{
_Connection.Open();
return _Connection.Query<Combination>(query).ToList();
}
}
public List GetData(int userId)
{
String query=“从myview”+”中选择*,其中userId=“+userId+”;”;
使用(System.Data.Common.DbConnection _Connection=database.Connection)
{
_Connection.Open();
return_Connection.Query(Query.ToList();
}
}
public static void process (List<Combination> list)
{
User myUser = new User(); myUser.Id = list[0].UserId; myUser.Name = list[0].UserName;
var myroles = new List<Role>(); var r = new Role(); string currentRole = list[0].RoleName;
var descList = new List<Description>(); var d = new Description();
// All stuff done in a single loop.
foreach (var v in list)
{
d = new Description() { Id = v.DescriptionId, RoleId = v.RoleId, Name = v.DescriptionName };
if (currentRole == v.RoleName)
{
r = new Role() { Id = v.RoleId, Name = v.RoleName, UserId = v.UserId, Descriptions = descList };
descList.Add(d);
}
else
{
myroles.Add(r);
descList = new List<Description>(); descList.Add(d);
currentRole = v.RoleName;
}
}
myroles.Add(r);
myUser.Roles = myroles;
Console.WriteLine("User: " + myUser.Name);
foreach (var myUserRole in myUser.Roles)
{
Console.WriteLine("Role: " + myUserRole.Name);
foreach (var description in myUserRole.Descriptions)
{
Console.WriteLine("Description: " + description.Name);
}
}
}
公共静态作废流程(列表)
{
用户myUser=new User();myUser.Id=list[0]。用户Id;myUser.Name=list[0]。用户名;
var myroles=new List();var r=new Role();string currentRole=List[0]。RoleName;
var descList=new List();var d=new Description();
//所有的事情都在一个循环中完成。
foreach(列表中的var v)
{
d=新描述(){Id=v.DescriptionId,RoleId=v.RoleId,Name=v.DescriptionName};
if(currentRole==v.RoleName)
{
r=newrole(){Id=v.RoleId,Name=v.RoleName,UserId=v.UserId,Descriptions=descList};
增加(d);
}
其他的
{
添加(r);
descList=new List();descList.Add(d);
currentRole=v.RoleName;
}
}
添加(r);
myUser.Roles=myroles;
Console.WriteLine(“用户:+myUser.Name”);
foreach(myUser.Roles中的var myUserRole)
{
Console.WriteLine(“角色:+myUserRole.Name”);
foreach(myUserRole.Descriptions中的变量描述)
{
Console.WriteLine(“Description:+Description.Name”);
}
}
}
从性能的角度来看,内部联接比其他形式的查询(如子查询、相关子查询等)更好。但归根结底,一切都归结为SQL执行计划。您的第一个选择是
public static void process (List<Combination> list)
{
User myUser = new User(); myUser.Id = list[0].UserId; myUser.Name = list[0].UserName;
var myroles = new List<Role>(); var r = new Role(); string currentRole = list[0].RoleName;
var descList = new List<Description>(); var d = new Description();
// All stuff done in a single loop.
foreach (var v in list)
{
d = new Description() { Id = v.DescriptionId, RoleId = v.RoleId, Name = v.DescriptionName };
if (currentRole == v.RoleName)
{
r = new Role() { Id = v.RoleId, Name = v.RoleName, UserId = v.UserId, Descriptions = descList };
descList.Add(d);
}
else
{
myroles.Add(r);
descList = new List<Description>(); descList.Add(d);
currentRole = v.RoleName;
}
}
myroles.Add(r);
myUser.Roles = myroles;
Console.WriteLine("User: " + myUser.Name);
foreach (var myUserRole in myUser.Roles)
{
Console.WriteLine("Role: " + myUserRole.Name);
foreach (var description in myUserRole.Descriptions)
{
Console.WriteLine("Description: " + description.Name);
}
}
}
var queryOne = "SELECT Id, Name FROM [User] WHERE Id = 1";
var queryTwo = "SELECT r.Id, r.UserId, r.Name FROM [User] u INNER JOIN [Role] r ON u.Id = r.UserId WHERE u.Id = 1";
var queryThree = "SELECT d.Id, d.RoleId, d.Name FROM [User] u INNER JOIN [Role] r ON u.Id = r.UserId INNER JOIN [Description] d ON r.Id = d.RoleId WHERE u.Id = 1";
var conn = new SqlConnection();
using (var con = conn)
{
var gridReader = con.QueryMultiple(queryOne + " " + queryTwo + " " + queryThree);
var user = gridReader.Read<User>().FirstOrDefault();
if (user == null)
{
return;
}
var roles = gridReader.Read<Role>().ToList();
var descriptions = gridReader.Read<Description>().ToLookup(d => d.RoleId);
user.Roles = roles;
roles.ForEach(r => r.Descriptions = descriptions[r.Id]);
}
public static void Main(String[] args)
{
int roleID = 6;
UserDataAccess dataAccess = new UserDataAccess();
IEnumerable<User> usersInRole = dataAccess.GetUsersByRoleID(roleID);
DisplayManager displayManager = new DisplayManager(usersInRole);
displayManager.DisplayInfo();
}