提交 60717dfe 编写于 作者: T thierry habart

Ticket #3 : Query with specified condition

上级 93aabfdf
<Project>
<PropertyGroup>
<VersionPrefix>1.0.0</VersionPrefix>
<VersionPrefix>2.0.0</VersionPrefix>
<Authors>SimpleIdServer</Authors>
<Owners>SimpleIdServer</Owners>
</PropertyGroup>
......
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
......@@ -9,4 +9,7 @@
<ItemGroup>
<Folder Include="Migrations\" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="2.2.0" />
</ItemGroup>
</Project>
......@@ -25,9 +25,9 @@ namespace EFCore.Cassandra.Samples
modelBuilder.ForCassandraAddKeyspace("cv", new KeyspaceReplicationSimpleStrategyClass(2));
modelBuilder.Entity<Applicant>()
.ToTable("applicants", "cv")
.HasKey(p => new { p.Id, p.LastName });
.HasKey(p => new { p.Id, p.Order });
modelBuilder.Entity<Applicant>()
.ForCassandraSetClusterColumns(s => new { s.LastName });
.ForCassandraSetClusterColumns(s => new { s.Order });
modelBuilder.Entity<Applicant>()
.Property(p => p.TimeUuid)
.HasConversion(new TimeUuidToGuidConverter());
......
......@@ -13,7 +13,7 @@ using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
namespace EFCore.Cassandra.Samples.Migrations
{
[DbContext(typeof(FakeDbContext))]
[Migration("20200520135456_Init")]
[Migration("20200521175814_Init")]
partial class Init
{
protected override void BuildTargetModel(ModelBuilder modelBuilder)
......@@ -29,8 +29,11 @@ namespace EFCore.Cassandra.Samples.Migrations
.HasColumnName("id")
.HasColumnType("uuid");
b.Property<string>("LastName")
.HasColumnType("text");
b.Property<int>("Order")
.HasColumnType("int");
b.Property<Guid>("ApplicantId")
.HasColumnType("uuid");
b.Property<BigInteger>("BigInteger")
.HasColumnType("varint");
......@@ -62,6 +65,9 @@ namespace EFCore.Cassandra.Samples.Migrations
b.Property<IPAddress>("Ip")
.HasColumnType("inet");
b.Property<string>("LastName")
.HasColumnType("text");
b.Property<LocalDate>("LocalDate")
.HasColumnType("date");
......@@ -86,11 +92,11 @@ namespace EFCore.Cassandra.Samples.Migrations
b.Property<Guid>("TimeUuid")
.HasColumnType("uuid");
b.HasKey("Id", "LastName");
b.HasKey("Id", "Order");
b.ToTable("applicants","cv");
b.HasAnnotation("Cassandra:ClusterColumns", new[] { "LastName" });
b.HasAnnotation("Cassandra:ClusterColumns", new[] { "Order" });
});
modelBuilder.Entity("EFCore.Cassandra.Samples.Models.CV", b =>
......@@ -99,6 +105,9 @@ namespace EFCore.Cassandra.Samples.Migrations
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<Guid>("CvId")
.HasColumnType("uuid");
b.Property<string>("Name")
.HasColumnType("text");
......
......@@ -20,7 +20,9 @@ namespace EFCore.Cassandra.Samples.Migrations
columns: table => new
{
id = table.Column<Guid>(nullable: false),
LastName = table.Column<string>(nullable: false),
Order = table.Column<int>(nullable: false),
ApplicantId = table.Column<Guid>(nullable: false),
LastName = table.Column<string>(nullable: true),
Long = table.Column<long>(nullable: false),
Bool = table.Column<bool>(nullable: false),
Decimal = table.Column<decimal>(nullable: false),
......@@ -42,7 +44,7 @@ namespace EFCore.Cassandra.Samples.Migrations
},
constraints: table =>
{
table.PrimaryKey("PK_applicants", x => new { x.id, x.LastName });
table.PrimaryKey("PK_applicants", x => new { x.id, x.Order });
});
migrationBuilder.CreateTable(
......@@ -51,6 +53,7 @@ namespace EFCore.Cassandra.Samples.Migrations
columns: table => new
{
Id = table.Column<Guid>(nullable: false),
CvId = table.Column<Guid>(nullable: false),
Name = table.Column<string>(nullable: true)
},
constraints: table =>
......
......@@ -27,8 +27,11 @@ namespace EFCore.Cassandra.Samples.Migrations
.HasColumnName("id")
.HasColumnType("uuid");
b.Property<string>("LastName")
.HasColumnType("text");
b.Property<int>("Order")
.HasColumnType("int");
b.Property<Guid>("ApplicantId")
.HasColumnType("uuid");
b.Property<BigInteger>("BigInteger")
.HasColumnType("varint");
......@@ -60,6 +63,9 @@ namespace EFCore.Cassandra.Samples.Migrations
b.Property<IPAddress>("Ip")
.HasColumnType("inet");
b.Property<string>("LastName")
.HasColumnType("text");
b.Property<LocalDate>("LocalDate")
.HasColumnType("date");
......@@ -84,11 +90,11 @@ namespace EFCore.Cassandra.Samples.Migrations
b.Property<Guid>("TimeUuid")
.HasColumnType("uuid");
b.HasKey("Id", "LastName");
b.HasKey("Id", "Order");
b.ToTable("applicants","cv");
b.HasAnnotation("Cassandra:ClusterColumns", new[] { "LastName" });
b.HasAnnotation("Cassandra:ClusterColumns", new[] { "Order" });
});
modelBuilder.Entity("EFCore.Cassandra.Samples.Models.CV", b =>
......@@ -97,6 +103,9 @@ namespace EFCore.Cassandra.Samples.Migrations
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<Guid>("CvId")
.HasColumnType("uuid");
b.Property<string>("Name")
.HasColumnType("text");
......
......@@ -11,6 +11,8 @@ namespace EFCore.Cassandra.Samples.Models
public class Applicant
{
public Guid Id { get; set; }
public int Order { get; set; }
public Guid ApplicantId { get; set; }
public string LastName { get; set; }
public long Long { get; set; }
public bool Bool { get; set; }
......
......@@ -7,6 +7,7 @@ namespace EFCore.Cassandra.Samples.Models
public class CV
{
public Guid Id { get; set; }
public Guid CvId { get; set; }
public string Name { get; set; }
}
}
......@@ -11,6 +11,9 @@ namespace EFCore.Cassandra.Samples
{
class Program
{
private static Guid ApplicantPartitionId = Guid.Parse("be2106c5-791f-45d2-890a-50fc221f96e8");
private static Guid ApplicantId = Guid.Parse("09e0f68e-8818-452a-9a47-3c8ca2c941c8");
static void Main(string[] args)
{
using (var dbContext = new FakeDbContext())
......@@ -19,26 +22,38 @@ namespace EFCore.Cassandra.Samples
var timeUuid = TimeUuid.NewId();
dbContext.Applicants.Add(BuildApplicant());
dbContext.SaveChanges();
Console.WriteLine("Applicant is added");
var appls = dbContext.Applicants.ToList();
Console.WriteLine($"Number of applicants '{dbContext.Applicants.LongCount()}'");
Console.WriteLine("Get applicants by partition key");
var filteredApplicants = dbContext.Applicants.Where(_ => _.Id == ApplicantPartitionId).ToList();
Console.WriteLine($"Number of applicants '{filteredApplicants.Count}'");
Console.WriteLine($"Number of applicants : {dbContext.Applicants.LongCount()}");
Console.WriteLine("Order applicants by 'order'");
var orderedApplicants = dbContext.Applicants.Where(_ => _.Id == ApplicantPartitionId).OrderBy(_ => _.Order).ToList();
Console.WriteLine($"Number of applicants {orderedApplicants.Count}");
Console.WriteLine("Update the applicant");
var applicant = dbContext.Applicants.First();
applicant = dbContext.Applicants.First();
applicant.Decimal = 10;
applicant.Dic = new Dictionary<string, string>
{
{ "toto", "toto" }
};
dbContext.SaveChanges();
Console.WriteLine("Applicant is updated");
Console.WriteLine("Remove the applicant");
applicant = dbContext.Applicants.First();
dbContext.Applicants.Remove(applicant);
dbContext.SaveChanges();
Console.WriteLine("Applicant is removed");
Console.WriteLine($"Number of applicants : {dbContext.Applicants.LongCount()}");
Console.WriteLine($"Number of applicants '{dbContext.Applicants.LongCount()}'");
Console.ReadLine();
}
}
......@@ -47,7 +62,9 @@ namespace EFCore.Cassandra.Samples
var timeUuid = TimeUuid.NewId();
return new Applicant
{
Id = Guid.NewGuid(),
Id = ApplicantPartitionId,
ApplicantId = ApplicantId,
Order = 0,
Lst = new List<string>
{
"1",
......
......@@ -141,6 +141,26 @@ namespace Microsoft.EntityFrameworkCore.Query
return selectExpression;
}
protected override Expression VisitSqlParameter(SqlParameterExpression sqlParameterExpression)
{
// Sql.Append(" ? ");
// return sqlParameterExpression;
var parameterNameInCommand = _sqlGenerationHelper.GenerateParameterName(sqlParameterExpression.Name).Replace("_", "").TrimStart(':');
if (Sql.Parameters.All(p => p.InvariantName != sqlParameterExpression.Name))
{
Sql.AddParameter(
sqlParameterExpression.Name,
parameterNameInCommand,
sqlParameterExpression.TypeMapping,
sqlParameterExpression.Type.IsNullableType());
}
// Sql.Append(_sqlGenerationHelper.GenerateParameterNamePlaceholder(sqlParameterExpression.Name));
Sql.Append($" :{parameterNameInCommand} ");
return sqlParameterExpression;
}
protected override void GenerateLimitOffset(SelectExpression selectExpression)
{
if (selectExpression.Limit != null)
......
// Copyright (c) SimpleIdServer. All rights reserved.
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
/*
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Query;
using Microsoft.EntityFrameworkCore.Query.Expressions;
using Microsoft.EntityFrameworkCore.Query.ExpressionVisitors;
using Microsoft.EntityFrameworkCore.Query.ExpressionVisitors.Internal;
using Microsoft.EntityFrameworkCore.Query.Internal;
using Remotion.Linq;
using Remotion.Linq.Clauses;
using Remotion.Linq.Clauses.ResultOperators;
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
*/
/*
namespace Microsoft.EntityFrameworkCore.Cassandra.Query
{
public class CassandraResultOperatorHandler : IResultOperatorHandler
{
private readonly IModel _model;
private readonly ISqlTranslatingExpressionVisitorFactory _sqlTranslatingExpressionVisitorFactory;
private readonly ISelectExpressionFactory _selectExpressionFactory;
private readonly IResultOperatorHandler _resultOperatorHandler;
private static Expression TransformClientExpression<TResult>(
HandlerContext handlerContext, bool throwOnNullResult = false)
=> new ResultTransformingExpressionVisitor<TResult>(
handlerContext.QueryModelVisitor.QueryCompilationContext,
throwOnNullResult)
.Visit(handlerContext.QueryModelVisitor.Expression);
private sealed class HandlerContext
{
private readonly IResultOperatorHandler _resultOperatorHandler;
private readonly ISqlTranslatingExpressionVisitorFactory _sqlTranslatingExpressionVisitorFactory;
public HandlerContext(
IResultOperatorHandler resultOperatorHandler,
IModel model,
ISqlTranslatingExpressionVisitorFactory sqlTranslatingExpressionVisitorFactory,
ISelectExpressionFactory selectExpressionFactory,
RelationalQueryModelVisitor queryModelVisitor,
ResultOperatorBase resultOperator,
QueryModel queryModel,
SelectExpression selectExpression)
{
_resultOperatorHandler = resultOperatorHandler;
_sqlTranslatingExpressionVisitorFactory = sqlTranslatingExpressionVisitorFactory;
Model = model;
SelectExpressionFactory = selectExpressionFactory;
QueryModelVisitor = queryModelVisitor;
ResultOperator = resultOperator;
QueryModel = queryModel;
SelectExpression = selectExpression;
}
public IModel Model { get; }
public ISelectExpressionFactory SelectExpressionFactory { get; }
public ResultOperatorBase ResultOperator { get; }
public SelectExpression SelectExpression { get; }
public QueryModel QueryModel { get; }
public RelationalQueryModelVisitor QueryModelVisitor { get; }
public Expression EvalOnServer => QueryModelVisitor.Expression;
public Expression EvalOnClient(bool requiresClientResultOperator = true)
{
QueryModelVisitor.RequiresClientResultOperator = requiresClientResultOperator;
return _resultOperatorHandler
.HandleResultOperator(QueryModelVisitor, ResultOperator, QueryModel);
}
public SqlTranslatingExpressionVisitor CreateSqlTranslatingVisitor()
=> _sqlTranslatingExpressionVisitorFactory.Create(QueryModelVisitor, SelectExpression);
}
public CassandraResultOperatorHandler(IModel model, ISqlTranslatingExpressionVisitorFactory sqlTranslatingExpressionVisitorFactory, ISelectExpressionFactory selectExpressionFactory, IResultOperatorHandler resultOperatorHandler) : base(model, sqlTranslatingExpressionVisitorFactory, selectExpressionFactory, resultOperatorHandler)
{
_model = model;
_sqlTranslatingExpressionVisitorFactory = sqlTranslatingExpressionVisitorFactory;
_selectExpressionFactory = selectExpressionFactory;
_resultOperatorHandler = resultOperatorHandler;
}
private static readonly Dictionary<Type, Func<HandlerContext, Expression>>
_resultHandlers = new Dictionary<Type, Func<HandlerContext, Expression>>
{
{ typeof(LongCountResultOperator), HandleLongCount },
{ typeof(CountResultOperator), HandleCount }
// { typeof(AllResultOperator), HandleAll },
// { typeof(AnyResultOperator), HandleAny },
// { typeof(AverageResultOperator), HandleAverage },
// { typeof(CastResultOperator), HandleCast },
// { typeof(ContainsResultOperator), HandleContains },
// { typeof(LongCountResultOperator), HandleLongCount },
// { typeof(DefaultIfEmptyResultOperator), HandleDefaultIfEmpty },
// { typeof(DistinctResultOperator), HandleDistinct },
// { typeof(FirstResultOperator), HandleFirst },
// { typeof(GroupResultOperator), HandleGroup },
// { typeof(LastResultOperator), HandleLast },
// { typeof(MaxResultOperator), HandleMax },
// { typeof(MinResultOperator), HandleMin },
// { typeof(SingleResultOperator), HandleSingle },
// { typeof(SkipResultOperator), HandleSkip },
// { typeof(SumResultOperator), HandleSum },
// { typeof(TakeResultOperator), HandleTake }
};
public override Expression HandleResultOperator(EntityQueryModelVisitor entityQueryModelVisitor, ResultOperatorBase resultOperator, QueryModel queryModel)
{
var relationalQueryModelVisitor
= (RelationalQueryModelVisitor)entityQueryModelVisitor;
var selectExpression
= relationalQueryModelVisitor
.TryGetQuery(queryModel.MainFromClause);
var handlerContext
= new HandlerContext(
_resultOperatorHandler,
_model,
_sqlTranslatingExpressionVisitorFactory,
_selectExpressionFactory,
relationalQueryModelVisitor,
resultOperator,
queryModel,
selectExpression);
if (relationalQueryModelVisitor.RequiresClientEval
|| relationalQueryModelVisitor.RequiresClientSelectMany
|| relationalQueryModelVisitor.RequiresClientJoin
|| relationalQueryModelVisitor.RequiresClientFilter
|| relationalQueryModelVisitor.RequiresClientOrderBy
|| relationalQueryModelVisitor.RequiresClientResultOperator
|| relationalQueryModelVisitor.RequiresStreamingGroupResultOperator
|| !_resultHandlers.TryGetValue(resultOperator.GetType(), out var resultHandler)
|| selectExpression == null)
{
return handlerContext.EvalOnClient();
}
else
{
return resultHandler(handlerContext);
}
}
private static Expression HandleCount(HandlerContext handlerContext)
{
PrepareSelectExpressionForAggregate(handlerContext.SelectExpression, handlerContext.QueryModel);
handlerContext.SelectExpression
.SetProjectionExpression(
new SqlFunctionExpression(
"COUNT",
typeof(int),
new[] { new SqlFragmentExpression("*") }));
handlerContext.SelectExpression.ClearOrderBy();
return TransformClientExpression<int>(handlerContext);
}
private static Expression HandleLongCount(HandlerContext handlerContext)
{
PrepareSelectExpressionForAggregate(handlerContext.SelectExpression, handlerContext.QueryModel);
handlerContext.SelectExpression
.SetProjectionExpression(
new SqlFunctionExpression(
"COUNT",
typeof(long),
new[] { new SqlFragmentExpression("*") }));
handlerContext.SelectExpression.ClearOrderBy();
return TransformClientExpression<long>(handlerContext);
}
}
}
*/
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册