有一个消息表。方案:
CREATE TABLE [dbo].[Messages] (
[Id] INT IDENTITY (1, 1) NOT NULL,
[DateCreate] DATETIME2 (7) DEFAULT (getdate()) NOT NULL,
[SenderId] INT NOT NULL,
[RecipientId] INT NOT NULL,
[TextMessage] NVARCHAR (MAX) NULL,
[IsReaded] BIT NOT NULL,
CONSTRAINT [PK_Messages] PRIMARY KEY CLUSTERED ([Id] ASC)
);
我想要一张桌子:
我还需要按[sender_id]分组并对输出进行排序。好。我提出一个简单的要求:
SELECT
message.SenderId AS sender_id,
COUNT(*) AS all_count_messages,
SUM(CAST(
CASE
WHEN IsReaded = 0
THEN 1
ELSE 0
END AS int)) as count_unreaded_messages,
MIN(message.DateCreate) AS most_unreaded
FROM
Messages AS message
GROUP BY
message.SenderId
ORDER BY
most_unreaded
演示结果:
sender_id all_count_messages unreaded_messages most_unreaded
2 3 2 2019-08-15 20:03:59.0000000
1 9 8 2019-08-15 20:04:59.0000000
答案很适合我。如何在EFCore上描述它?
尝试
var chats = from my_messages in db.Messages
group my_messages by my_messages.SenderId into g
select
new
{
sender_id = g.Key,
all_count_messages = g.Count(),
unreaded_messages = from sub_messages in db.Messages where sub_messages.SenderId == g.Key && !sub_messages.IsReaded group sub_messages by sub_messages.SenderId into sub_g select sub_g.Count(),
most_unreaded = from sub_messages in db.Messages where sub_messages.SenderId == g.Key && !sub_messages.IsReaded group sub_messages by sub_messages.SenderId into sub_g select sub_g.Min(x => x.DateCreate)
};
foreach (var chat in chats) // so, too, has tried: chats.Include(x=>x.unreaded_messages).Include(x => x.most_unreaded)
{
}
在foreach (var chat in chats)
中出现错误
An unhandled exception occurred while processing the request.
ArgumentException: must be reducible node
System.Linq.Expressions.Expression.ReduceAndCheck()
我尝试其他方式:
var chats = db.Messages.AsNoTracking().FromSql(
"SELECT" +
" message.SenderId AS sender_id," +
" COUNT(*) AS all_count_messages," +
" SUM(CAST(" +
" CASE" +
" WHEN IsReaded = 0" +
" THEN 1" +
" ELSE 0" +
" END AS int)) as count_unreaded_messages," +
" MIN(message.DateCreate) AS most_unreaded " +
"FROM " +
" Messages AS message " +
"GROUP BY " +
" message.SenderId " +
"ORDER BY" +
" most_unreaded ");
foreach (var chat in chats)
{
}
在foreach (var chat in chats)
中出现错误
InvalidOperationException: The required column 'Id' was not present in the results of a 'FromSql' operation.
Microsoft.EntityFrameworkCore.Query.Sql.Internal.FromSqlNonComposedQuerySqlGenerator.CreateValueBufferFactory(IRelationalValueBufferFactoryFactory relationalValueBufferFactoryFactory, DbDataReader dataReader)
答案 0 :(得分:0)
您需要在查询的select语句中添加Id列。应该是
"SELECT" +
" message.Id AS Id," +
" message.SenderId AS sender_id," +
...
答案 1 :(得分:0)
感谢@ilkerkaran那里的链接https://stackoverflow.com/a/28627991/2630427,我发现并稍微改变了动态请求的方法
.net asp core 2.2的一点完成的实现:
public class AppDbContext : DbContext
{
public DbSet<Message> Messages { get; set; }
IOptions<AppConfig> app_config;
public AppDbContext(DbContextOptions<AppDbContext> options, IOptions<AppConfig> _app_config)
: base(options)
{
app_config = _app_config;
Database.EnsureCreated();
}
public IEnumerable<dynamic> DynamicListFromSql(string Sql, Dictionary<string, object> Params = null)
{
using (var cmd = Database.GetDbConnection().CreateCommand())
{
cmd.CommandText = Sql;
if (cmd.Connection.State != ConnectionState.Open) { cmd.Connection.Open(); }
if (Params != null)
foreach (KeyValuePair<string, object> p in Params)
{
DbParameter dbParameter = cmd.CreateParameter();
dbParameter.ParameterName = p.Key;
dbParameter.Value = p.Value;
cmd.Parameters.Add(dbParameter);
}
using (var dataReader = cmd.ExecuteReader())
{
while (dataReader.Read())
{
var row = new ExpandoObject() as IDictionary<string, object>;
for (var fieldCount = 0; fieldCount < dataReader.FieldCount; fieldCount++)
{
row.Add(dataReader.GetName(fieldCount), dataReader[fieldCount]);
}
yield return row;
}
}
}
}
}
string query =
"SELECT" +
" message.SenderId AS sender_id," +
" COUNT(*) AS all_count_messages," +
" (SELECT COUNT(*) FROM Messages AS sub_message WHERE sub_message.SenderId = message.SenderId AND sub_message.IsReaded = 0) AS unreaded_messages," +
" (SELECT MIN(sub_message.DateCreate) FROM Messages AS sub_message WHERE sub_message.SenderId = message.SenderId) AS most_unreaded " +
"FROM " +
" Messages AS message " +
"GROUP BY " +
" message.SenderId " +
"ORDER BY" +
" most_unreaded ";
//"OFFSET 0 ROWS FETCH NEXT 10 ROWS ONLY", offset, fetch);
foreach (var chat in db.DynamicListFromSql(query))
{
}