From dcb92f69523af3255f98a545cf85f4ba2908d526 Mon Sep 17 00:00:00 2001 From: yangzhongke Date: Sat, 30 Oct 2021 01:31:04 +0800 Subject: [PATCH] =?UTF-8?q?=E7=94=A8=E6=B4=8B=E8=91=B1=E6=9E=B6=E6=9E=84?= =?UTF-8?q?=E9=87=8D=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../EFcoreOneToOneBug/A.cs" | 9 +- .../EFcoreOneToOneBug/B.cs" | 9 +- .../20211029113915_Init.Designer.cs" | 80 +++++++++++++++ .../Migrations/20211029113915_Init.cs" | 59 +++++++++++ .../20211029115239_Init2.Designer.cs" | 83 ++++++++++++++++ .../Migrations/20211029115239_Init2.cs" | 26 +++++ .../Migrations/MyDbContextModelSnapshot.cs" | 81 +++++++++++++++ .../EFcoreOneToOneBug/MyDbContext.cs" | 5 +- .../EFcoreOneToOneBug/Programe.cs" | 7 +- .../Users.Domain/CheckCodeResult.cs" | 7 ++ .../Users.Domain/Entities/IAggregateRoot.cs" | 0 .../Users.Domain/Entities/PhoneNumber.cs" | 0 .../Users.Domain/Entities/User.cs" | 6 +- .../Users.Domain/Entities/UserAccessFail.cs" | 0 .../Entities/UserLoginHistory.cs" | 0 .../Users.Domain/ISmsCodeSender.cs" | 2 +- .../Users.Domain/IUserDomainRepository.cs" | 19 ++++ .../Users.Domain/UserDomainService.cs" | 96 +++++++++++++++--- .../Users.Infrastructure/ExpressionHelper.cs" | 22 +++-- .../UserDomainRepository.cs" | 67 +++++++++++++ .../Controllers/LoginController.cs" | 98 +++++-------------- .../Controllers/UsersMgrController.cs" | 12 +-- .../Events/UserAccessResultEventHandler.cs" | 9 +- .../Users.WebAPI/Program.cs" | 3 +- .../Users.WebAPI/UnitOfWorkFilter.cs" | 12 +-- .../Users.WebAPI/UserApplicationService.cs" | 38 ------- .../EFCore/ExpressionHelper.cs" | 10 +- 27 files changed, 588 insertions(+), 172 deletions(-) create mode 100644 "\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/EFcoreOneToOneBug/Migrations/20211029113915_Init.Designer.cs" create mode 100644 "\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/EFcoreOneToOneBug/Migrations/20211029113915_Init.cs" create mode 100644 "\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/EFcoreOneToOneBug/Migrations/20211029115239_Init2.Designer.cs" create mode 100644 "\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/EFcoreOneToOneBug/Migrations/20211029115239_Init2.cs" create mode 100644 "\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/EFcoreOneToOneBug/Migrations/MyDbContextModelSnapshot.cs" create mode 100644 "\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/Users.Domain/CheckCodeResult.cs" rename "\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/Users.Domain/IAggregateRoot.cs" => "\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/Users.Domain/Entities/IAggregateRoot.cs" (100%) rename "\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/Users.Domain/PhoneNumber.cs" => "\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/Users.Domain/Entities/PhoneNumber.cs" (100%) rename "\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/Users.Domain/User.cs" => "\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/Users.Domain/Entities/User.cs" (79%) rename "\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/Users.Domain/UserAccessFail.cs" => "\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/Users.Domain/Entities/UserAccessFail.cs" (100%) rename "\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/Users.Domain/UserLoginHistory.cs" => "\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/Users.Domain/Entities/UserLoginHistory.cs" (100%) rename "\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/Users.Infrastructure/ISmsCodeSender.cs" => "\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/Users.Domain/ISmsCodeSender.cs" (81%) create mode 100644 "\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/Users.Domain/IUserDomainRepository.cs" create mode 100644 "\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/Users.Infrastructure/UserDomainRepository.cs" delete mode 100644 "\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/Users.WebAPI/UserApplicationService.cs" diff --git "a/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/EFcoreOneToOneBug/A.cs" "b/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/EFcoreOneToOneBug/A.cs" index 009bed5..7a6da08 100644 --- "a/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/EFcoreOneToOneBug/A.cs" +++ "b/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/EFcoreOneToOneBug/A.cs" @@ -1,15 +1,10 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace EFcoreOneToOneBug +namespace EFcoreOneToOneBug { class A { public Guid Id { get; set; } public string Name { get; set; } public B? B { get; set; } + public Guid? BId { get; set; } } } diff --git "a/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/EFcoreOneToOneBug/B.cs" "b/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/EFcoreOneToOneBug/B.cs" index 0f6e1a8..f62851d 100644 --- "a/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/EFcoreOneToOneBug/B.cs" +++ "b/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/EFcoreOneToOneBug/B.cs" @@ -1,15 +1,10 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace EFcoreOneToOneBug +namespace EFcoreOneToOneBug { class B { public Guid Id { get; set; } public int Age { get; set; } public A A { get; set; } + public Guid AId { get; set; } } } diff --git "a/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/EFcoreOneToOneBug/Migrations/20211029113915_Init.Designer.cs" "b/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/EFcoreOneToOneBug/Migrations/20211029113915_Init.Designer.cs" new file mode 100644 index 0000000..fdbf19a --- /dev/null +++ "b/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/EFcoreOneToOneBug/Migrations/20211029113915_Init.Designer.cs" @@ -0,0 +1,80 @@ +// +using System; +using EFcoreOneToOneBug; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace EFcoreOneToOneBug.Migrations +{ + [DbContext(typeof(MyDbContext))] + [Migration("20211029113915_Init")] + partial class Init + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "6.0.0-rc.2.21480.5") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder, 1L, 1); + + modelBuilder.Entity("EFcoreOneToOneBug.A", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.ToTable("A"); + }); + + modelBuilder.Entity("EFcoreOneToOneBug.B", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("AId") + .HasColumnType("uniqueidentifier"); + + b.Property("Age") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("AId") + .IsUnique(); + + b.ToTable("B"); + }); + + modelBuilder.Entity("EFcoreOneToOneBug.B", b => + { + b.HasOne("EFcoreOneToOneBug.A", "A") + .WithOne("B") + .HasForeignKey("EFcoreOneToOneBug.B", "AId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("A"); + }); + + modelBuilder.Entity("EFcoreOneToOneBug.A", b => + { + b.Navigation("B"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git "a/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/EFcoreOneToOneBug/Migrations/20211029113915_Init.cs" "b/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/EFcoreOneToOneBug/Migrations/20211029113915_Init.cs" new file mode 100644 index 0000000..10ec3e9 --- /dev/null +++ "b/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/EFcoreOneToOneBug/Migrations/20211029113915_Init.cs" @@ -0,0 +1,59 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace EFcoreOneToOneBug.Migrations +{ + public partial class Init : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "A", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + Name = table.Column(type: "nvarchar(max)", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_A", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "B", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + Age = table.Column(type: "int", nullable: false), + AId = table.Column(type: "uniqueidentifier", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_B", x => x.Id); + table.ForeignKey( + name: "FK_B_A_AId", + column: x => x.AId, + principalTable: "A", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateIndex( + name: "IX_B_AId", + table: "B", + column: "AId", + unique: true); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "B"); + + migrationBuilder.DropTable( + name: "A"); + } + } +} diff --git "a/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/EFcoreOneToOneBug/Migrations/20211029115239_Init2.Designer.cs" "b/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/EFcoreOneToOneBug/Migrations/20211029115239_Init2.Designer.cs" new file mode 100644 index 0000000..dacb76c --- /dev/null +++ "b/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/EFcoreOneToOneBug/Migrations/20211029115239_Init2.Designer.cs" @@ -0,0 +1,83 @@ +// +using System; +using EFcoreOneToOneBug; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace EFcoreOneToOneBug.Migrations +{ + [DbContext(typeof(MyDbContext))] + [Migration("20211029115239_Init2")] + partial class Init2 + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "6.0.0-rc.2.21480.5") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder, 1L, 1); + + modelBuilder.Entity("EFcoreOneToOneBug.A", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("BId") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.ToTable("A"); + }); + + modelBuilder.Entity("EFcoreOneToOneBug.B", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("AId") + .HasColumnType("uniqueidentifier"); + + b.Property("Age") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("AId") + .IsUnique(); + + b.ToTable("B"); + }); + + modelBuilder.Entity("EFcoreOneToOneBug.B", b => + { + b.HasOne("EFcoreOneToOneBug.A", "A") + .WithOne("B") + .HasForeignKey("EFcoreOneToOneBug.B", "AId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("A"); + }); + + modelBuilder.Entity("EFcoreOneToOneBug.A", b => + { + b.Navigation("B"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git "a/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/EFcoreOneToOneBug/Migrations/20211029115239_Init2.cs" "b/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/EFcoreOneToOneBug/Migrations/20211029115239_Init2.cs" new file mode 100644 index 0000000..0d43432 --- /dev/null +++ "b/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/EFcoreOneToOneBug/Migrations/20211029115239_Init2.cs" @@ -0,0 +1,26 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace EFcoreOneToOneBug.Migrations +{ + public partial class Init2 : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "BId", + table: "A", + type: "uniqueidentifier", + nullable: true); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "BId", + table: "A"); + } + } +} diff --git "a/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/EFcoreOneToOneBug/Migrations/MyDbContextModelSnapshot.cs" "b/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/EFcoreOneToOneBug/Migrations/MyDbContextModelSnapshot.cs" new file mode 100644 index 0000000..74f2aa4 --- /dev/null +++ "b/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/EFcoreOneToOneBug/Migrations/MyDbContextModelSnapshot.cs" @@ -0,0 +1,81 @@ +// +using System; +using EFcoreOneToOneBug; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace EFcoreOneToOneBug.Migrations +{ + [DbContext(typeof(MyDbContext))] + partial class MyDbContextModelSnapshot : ModelSnapshot + { + protected override void BuildModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "6.0.0-rc.2.21480.5") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder, 1L, 1); + + modelBuilder.Entity("EFcoreOneToOneBug.A", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("BId") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.ToTable("A"); + }); + + modelBuilder.Entity("EFcoreOneToOneBug.B", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("AId") + .HasColumnType("uniqueidentifier"); + + b.Property("Age") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("AId") + .IsUnique(); + + b.ToTable("B"); + }); + + modelBuilder.Entity("EFcoreOneToOneBug.B", b => + { + b.HasOne("EFcoreOneToOneBug.A", "A") + .WithOne("B") + .HasForeignKey("EFcoreOneToOneBug.B", "AId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("A"); + }); + + modelBuilder.Entity("EFcoreOneToOneBug.A", b => + { + b.Navigation("B"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git "a/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/EFcoreOneToOneBug/MyDbContext.cs" "b/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/EFcoreOneToOneBug/MyDbContext.cs" index 25c7153..d1424e3 100644 --- "a/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/EFcoreOneToOneBug/MyDbContext.cs" +++ "b/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/EFcoreOneToOneBug/MyDbContext.cs" @@ -9,13 +9,16 @@ class MyDbContext:DbContext protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { base.OnConfiguring(optionsBuilder); + optionsBuilder.LogTo(Console.WriteLine); optionsBuilder.UseSqlServer("Server=.;Database=testbug;Trusted_Connection=True;"); } protected override void OnModelCreating(ModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); - modelBuilder.Entity().HasOne(x => x.B).WithOne(x=>x.A); + modelBuilder.Entity().HasOne(x => x.B).WithOne(x => x.A) + //.IsRequired(false) + .HasForeignKey(x => x.AId);//.HasPrincipalKey(x=>x.BId); } } } diff --git "a/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/EFcoreOneToOneBug/Programe.cs" "b/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/EFcoreOneToOneBug/Programe.cs" index 997b482..62df3a3 100644 --- "a/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/EFcoreOneToOneBug/Programe.cs" +++ "b/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/EFcoreOneToOneBug/Programe.cs" @@ -1,7 +1,10 @@ using EFcoreOneToOneBug; +using Microsoft.EntityFrameworkCore; using MyDbContext ctx = new MyDbContext(); -A a1 = new A(); +A a1 = new A() { Id=Guid.NewGuid(),Name="ABC"}; ctx.A.Add(a1); ctx.SaveChanges(); -A a2 = \ No newline at end of file +A a2 = ctx.A.Include(x=>x.B).Single(x=>x.Id==a1.Id); +a1.B = new B() { Id = Guid.NewGuid(), Age = 18 }; +ctx.SaveChanges(); \ No newline at end of file diff --git "a/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/Users.Domain/CheckCodeResult.cs" "b/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/Users.Domain/CheckCodeResult.cs" new file mode 100644 index 0000000..fb74d64 --- /dev/null +++ "b/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/Users.Domain/CheckCodeResult.cs" @@ -0,0 +1,7 @@ +namespace Users.Domain +{ + public enum CheckCodeResult + { + OK, PhoneNumberNotFound, Lockout,CodeError + } +} diff --git "a/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/Users.Domain/IAggregateRoot.cs" "b/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/Users.Domain/Entities/IAggregateRoot.cs" similarity index 100% rename from "\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/Users.Domain/IAggregateRoot.cs" rename to "\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/Users.Domain/Entities/IAggregateRoot.cs" diff --git "a/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/Users.Domain/PhoneNumber.cs" "b/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/Users.Domain/Entities/PhoneNumber.cs" similarity index 100% rename from "\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/Users.Domain/PhoneNumber.cs" rename to "\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/Users.Domain/Entities/PhoneNumber.cs" diff --git "a/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/Users.Domain/User.cs" "b/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/Users.Domain/Entities/User.cs" similarity index 79% rename from "\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/Users.Domain/User.cs" rename to "\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/Users.Domain/Entities/User.cs" index 0a8a680..4a35c8a 100644 --- "a/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/Users.Domain/User.cs" +++ "b/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/Users.Domain/Entities/User.cs" @@ -14,10 +14,8 @@ public User(PhoneNumber phoneNumber) { Id= Guid.NewGuid(); PhoneNumber = phoneNumber; - //AccessFail不能为空,否则如果AccessFail一开始为null, - //当我们给AccessFail赋值后,立即修改AccessFail中的属性值 - //那么AccessFail的状态就从Added变成Modified了,然后保存就会出错, - //这个应该算是EFCore的bug + //AccessFail不能为空,否则有bug + //https://github.com/dotnet/efcore/issues/26489 this.AccessFail = new UserAccessFail(this); } public bool HasPassword() diff --git "a/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/Users.Domain/UserAccessFail.cs" "b/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/Users.Domain/Entities/UserAccessFail.cs" similarity index 100% rename from "\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/Users.Domain/UserAccessFail.cs" rename to "\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/Users.Domain/Entities/UserAccessFail.cs" diff --git "a/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/Users.Domain/UserLoginHistory.cs" "b/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/Users.Domain/Entities/UserLoginHistory.cs" similarity index 100% rename from "\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/Users.Domain/UserLoginHistory.cs" rename to "\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/Users.Domain/Entities/UserLoginHistory.cs" diff --git "a/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/Users.Infrastructure/ISmsCodeSender.cs" "b/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/Users.Domain/ISmsCodeSender.cs" similarity index 81% rename from "\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/Users.Infrastructure/ISmsCodeSender.cs" rename to "\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/Users.Domain/ISmsCodeSender.cs" index 965ece0..e0475d3 100644 --- "a/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/Users.Infrastructure/ISmsCodeSender.cs" +++ "b/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/Users.Domain/ISmsCodeSender.cs" @@ -1,6 +1,6 @@ using Users.Domain; -namespace Users.Infrastructure +namespace Users.Domain { public interface ISmsCodeSender { diff --git "a/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/Users.Domain/IUserDomainRepository.cs" "b/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/Users.Domain/IUserDomainRepository.cs" new file mode 100644 index 0000000..c47dee4 --- /dev/null +++ "b/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/Users.Domain/IUserDomainRepository.cs" @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Users.Domain.Events; + +namespace Users.Domain +{ + public interface IUserDomainRepository + { + Task FindOneAsync(PhoneNumber phoneNumber); + Task FindOneAsync(Guid userId); + Task AddNewLoginHistoryAsync(PhoneNumber phoneNumber, string msg); + Task PublishEventAsync(UserAccessResultEvent eventData); + Task SavePhoneCodeAsync(PhoneNumber phoneNumber, string code); + Task RetrievePhoneCodeAsync(PhoneNumber phoneNumber); + } +} diff --git "a/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/Users.Domain/UserDomainService.cs" "b/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/Users.Domain/UserDomainService.cs" index 4ab4ce3..d03ebac 100644 --- "a/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/Users.Domain/UserDomainService.cs" +++ "b/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/Users.Domain/UserDomainService.cs" @@ -1,29 +1,99 @@ -namespace Users.Domain +using Users.Domain.Events; + +namespace Users.Domain { public class UserDomainService { - //参数需要是User,而不是phoneNum,因为领域层不碰数据库 - public UserAccessResult CheckLogin(User user,string password) + private readonly IUserDomainRepository repository; + private readonly ISmsCodeSender smsSender; + + public UserDomainService(IUserDomainRepository repository, ISmsCodeSender smsSender) + { + this.repository = repository; + this.smsSender = smsSender; + } + + public async Task CheckLoginAsync(PhoneNumber phoneNum,string password) { - if(IsLockOut(user)) + User? user = await repository.FindOneAsync(phoneNum); + UserAccessResult result; + if (user == null) + { + result = UserAccessResult.PhoneNumberNotFound; + } + else if (IsLockOut(user)) + { + result = UserAccessResult.Lockout; + } + else if(user.HasPassword()==false) + { + result = UserAccessResult.NoPassword; + } + else if(user.CheckPassword(password)) + { + result = UserAccessResult.OK; + } + else + { + result = UserAccessResult.PasswordError; + } + if(user!=null) + { + if (result == UserAccessResult.OK) + { + this.ResetAccessFail(user); + } + else + { + this.AccessFail(user); + } + } + UserAccessResultEvent eventItem = new(phoneNum, result); + await repository.PublishEventAsync(eventItem); + return result; + } + + public async Task SendCodeAsync(PhoneNumber phoneNum) + { + var user = await repository.FindOneAsync(phoneNum); + if (user == null) + { + return UserAccessResult.PhoneNumberNotFound; + } + if (IsLockOut(user)) { - this.AccessFail(user); return UserAccessResult.Lockout; } - if(user.HasPassword()==false) + string code = Random.Shared.Next(1000, 9999).ToString(); + await repository.SavePhoneCodeAsync(phoneNum, code); + await smsSender.SendCodeAsync(phoneNum, code); + return UserAccessResult.OK; + } + + public async Task CheckCodeAsync(PhoneNumber phoneNum,string code) + { + var user = await repository.FindOneAsync(phoneNum); + if (user == null) + { + return CheckCodeResult.PhoneNumberNotFound; + } + if (IsLockOut(user)) + { + return CheckCodeResult.Lockout; + } + string? codeInServer = await repository.RetrievePhoneCodeAsync(phoneNum); + if (string.IsNullOrEmpty(codeInServer)) { - this.AccessFail(user); - return UserAccessResult.NoPassword; + return CheckCodeResult.CodeError; } - if(user.CheckPassword(password)) + if (code == codeInServer) { - this.ResetAccessFail(user); - return UserAccessResult.OK; + return CheckCodeResult.OK; } else { - this.AccessFail(user); - return UserAccessResult.PasswordError; + AccessFail(user); + return CheckCodeResult.CodeError; } } diff --git "a/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/Users.Infrastructure/ExpressionHelper.cs" "b/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/Users.Infrastructure/ExpressionHelper.cs" index b81a4ee..7244cbb 100644 --- "a/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/Users.Infrastructure/ExpressionHelper.cs" +++ "b/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/Users.Infrastructure/ExpressionHelper.cs" @@ -5,15 +5,21 @@ namespace Users.Infrastructure { public class ExpressionHelper { - public static Expression> MakeEqual(Expression> propAccessor, TProp other) + public static Expression> MakeEqual(Expression> propAccessor, TProp? other) + where TItem : class + where TProp : class { var e1 = propAccessor.Parameters.Single();//提取出来参数 - BinaryExpression? conditionalExpr=null; - foreach(var prop in typeof(TProp).GetProperties()) + BinaryExpression? conditionalExpr = null; + foreach (var prop in typeof(TProp).GetProperties()) { BinaryExpression equalExpr; //other的prop属性的值 - object? otherValue = prop.GetValue(other); + object? otherValue = null; + if (other != null) + { + otherValue = prop.GetValue(other); + } Type propType = prop.PropertyType; //访问待比较的属性 var memAccessProp = MakeMemberAccess( @@ -23,16 +29,16 @@ public class ExpressionHelper var constValue = Convert(Constant(otherValue), propType); if (propType.IsPrimitive)//基本数据类型和复杂类型比较方法不一样 { - equalExpr=Equal(memAccessProp, constValue); + equalExpr = Equal(memAccessProp, constValue); } else { equalExpr = MakeBinary(ExpressionType.Equal, - memAccessProp,constValue, false, + memAccessProp, constValue, false, prop.PropertyType.GetMethod("op_Equality") ); } - if(conditionalExpr==null) + if (conditionalExpr == null) { conditionalExpr = equalExpr; } @@ -41,7 +47,7 @@ public class ExpressionHelper conditionalExpr = AndAlso(conditionalExpr, equalExpr); } } - if(conditionalExpr==null) + if (conditionalExpr == null) { throw new ArgumentException("There should be at least one property."); } diff --git "a/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/Users.Infrastructure/UserDomainRepository.cs" "b/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/Users.Infrastructure/UserDomainRepository.cs" new file mode 100644 index 0000000..48cb0e9 --- /dev/null +++ "b/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/Users.Infrastructure/UserDomainRepository.cs" @@ -0,0 +1,67 @@ +using MediatR; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Caching.Distributed; +using System.Text; +using Users.Domain; +using Users.Domain.Events; +using static Users.Infrastructure.ExpressionHelper; + +namespace Users.Infrastructure +{ + public class UserDomainRepository : IUserDomainRepository + { + private readonly UserDbContext dbCtx; + private readonly IDistributedCache distCache; + private readonly IMediator mediator; + + public UserDomainRepository(UserDbContext dbCtx, IDistributedCache distCache, IMediator mediator) + { + this.dbCtx = dbCtx; + this.distCache = distCache; + this.mediator = mediator; + } + public Task FindOneAsync(PhoneNumber phoneNumber) + { + ////if(dbCtx.Users.Any(u=>u.PhoneNumber.RegionCode==req.RegionCode&&u.PhoneNumber.Numbe + return dbCtx.Users.Include(u => u.AccessFail).SingleOrDefaultAsync(MakeEqual((User u) => u.PhoneNumber, phoneNumber)); + } + + public Task FindOneAsync(Guid userId) + { + return dbCtx.Users.Include(u => u.AccessFail) + .SingleOrDefaultAsync(u => u.Id == userId); + } + + public async Task AddNewLoginHistoryAsync(PhoneNumber phoneNumber, string msg) + { + var user = await FindOneAsync(phoneNumber); + UserLoginHistory history = new UserLoginHistory(user?.Id, + phoneNumber, msg); + dbCtx.LoginHistories.Add(history); + //这里不保存 + } + + public Task RetrievePhoneCodeAsync(PhoneNumber phoneNumber) + { + string fullNumber = phoneNumber.RegionCode + phoneNumber.Number; + string cacheKey = $"LoginByPhoneAndCode_Code_{fullNumber}"; + string? code = distCache.GetString(cacheKey); + distCache.Remove(cacheKey); + return Task.FromResult(code); + } + + public Task PublishEventAsync(UserAccessResultEvent eventData) + { + return mediator.Publish(eventData); + } + + public Task SavePhoneCodeAsync(PhoneNumber phoneNumber, string code) + { + string fullNumber = phoneNumber.RegionCode + phoneNumber.Number; + var options = new DistributedCacheEntryOptions(); + options.AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(60); + distCache.SetString($"LoginByPhoneAndCode_Code_{fullNumber}", code, options); + return Task.CompletedTask; + } + } +} diff --git "a/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/Users.WebAPI/Controllers/LoginController.cs" "b/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/Users.WebAPI/Controllers/LoginController.cs" index 034b39f..85031be 100644 --- "a/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/Users.WebAPI/Controllers/LoginController.cs" +++ "b/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/Users.WebAPI/Controllers/LoginController.cs" @@ -1,8 +1,5 @@ -using MediatR; -using Microsoft.AspNetCore.Mvc; -using Microsoft.Extensions.Caching.Distributed; +using Microsoft.AspNetCore.Mvc; using Users.Domain; -using Users.Domain.Events; using Users.Infrastructure; namespace Users.WebAPI.Controllers.Login @@ -13,48 +10,27 @@ namespace Users.WebAPI.Controllers.Login public class LoginController : ControllerBase { private readonly UserDomainService domainService; - private readonly UserApplicationService appService; - private readonly ISmsCodeSender smsSender; - private readonly IDistributedCache distCache; - private readonly IMediator mediator; - public LoginController(UserDomainService domainService, - UserApplicationService appService, - ISmsCodeSender smsSender, - IDistributedCache distCache, IMediator mediator) + public LoginController(UserDomainService domainService) { this.domainService = domainService; - this.smsSender = smsSender; - this.distCache = distCache; - this.appService = appService; - this.mediator = mediator; } [HttpPut] public async Task LoginByPhoneAndPwd(LoginByPhoneAndPwdRequest req) { var phoneNum = req.PhoneNumber; - var user = await appService.FindOneAsync(req.PhoneNumber); - if (user == null) - { - await mediator.Publish(new UserAccessResultEvent(phoneNum, - UserAccessResult.PhoneNumberNotFound)); - return BadRequest("手机号或者密码错误");//避免泄密,不能404 - } - var result = domainService.CheckLogin(user, req.Password); + var result = await domainService.CheckLoginAsync(phoneNum, req.Password); switch(result) { case UserAccessResult.OK: - await mediator.Publish(new UserAccessResultEvent(phoneNum, - UserAccessResult.OK)); return Ok("登录成功"); + case UserAccessResult.PhoneNumberNotFound: + return BadRequest("手机号或者密码错误");//避免泄密,不能404 case UserAccessResult.Lockout: - await mediator.Publish(new UserAccessResultEvent(phoneNum, - UserAccessResult.Lockout)); return BadRequest("用户被锁定,请稍后再试"); case UserAccessResult.NoPassword: case UserAccessResult.PasswordError: - await mediator.Publish(new UserAccessResultEvent(phoneNum,result)); return BadRequest("手机号或者密码错误"); default: throw new NotImplementedException(); @@ -62,56 +38,36 @@ public async Task LoginByPhoneAndPwd(LoginByPhoneAndPwdRequest re } [HttpPost] - public async Task SendLoginByPhoneAndCode(SendLoginByPhoneAndCodeRequest req) + public async Task SendCodeByPhone(SendLoginByPhoneAndCodeRequest req) { - var user = await appService.FindOneAsync(req.PhoneNumber); - if (user == null) - { - return BadRequest("请求错误");//避免泄密 - } - if(domainService.IsLockOut(user)) + var result = await domainService.SendCodeAsync(req.PhoneNumber); + switch(result) { - return BadRequest("用户被锁定,请稍后再试"); + case UserAccessResult.OK: + return Ok("验证码已发出"); + case UserAccessResult.Lockout: + return BadRequest("用户被锁定,请稍后再试"); + default: + return BadRequest("请求错误");//避免泄密,不说细节 } - string code = Random.Shared.Next(1000, 9999).ToString(); - var phoneNum = req.PhoneNumber; - string fullNumber = phoneNum.RegionCode + phoneNum.Number; - var options = new DistributedCacheEntryOptions(); - options.AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(60); - distCache.SetString($"LoginByPhoneAndCode_Code_{fullNumber}", code, options); - await smsSender.SendCodeAsync(phoneNum, code); - return Ok("验证码已发出"); } [HttpPost] - public async Task CheckLoginByPhoneAndCode(CheckLoginByPhoneAndCodeRequest req) + public async Task CheckCode(CheckLoginByPhoneAndCodeRequest req) { - var user = await appService.FindOneAsync(req.PhoneNumber); - if (user == null) - { - return BadRequest("请求错误");//避免泄密 - } - if (domainService.IsLockOut(user)) - { - return BadRequest("用户被锁定,请稍后再试"); - } - var phoneNum = req.PhoneNumber; - string fullNumber = phoneNum.RegionCode + phoneNum.Number; - string cacheKey = $"LoginByPhoneAndCode_Code_{fullNumber}"; - string code = distCache.GetString(cacheKey); - if(string.IsNullOrEmpty(code)) - { - return BadRequest("验证码已过期"); - } - if(code==req.Code) - { - return Ok("登录成功"); - } - else + var result = await domainService.CheckCodeAsync(req.PhoneNumber, req.Code); + switch(result) { - distCache.Remove(cacheKey); - domainService.AccessFail(user); - return BadRequest("验证码错误,请重启验证"); + case CheckCodeResult.OK: + return Ok("登录成功"); + case CheckCodeResult.PhoneNumberNotFound: + return BadRequest("请求错误");//避免泄密 + case CheckCodeResult.Lockout: + return BadRequest("用户被锁定,请稍后再试"); + case CheckCodeResult.CodeError: + return BadRequest("验证码错误"); + default: + throw new NotImplementedException(); } } } diff --git "a/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/Users.WebAPI/Controllers/UsersMgrController.cs" "b/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/Users.WebAPI/Controllers/UsersMgrController.cs" index da8b824..9884831 100644 --- "a/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/Users.WebAPI/Controllers/UsersMgrController.cs" +++ "b/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/Users.WebAPI/Controllers/UsersMgrController.cs" @@ -12,19 +12,19 @@ public class UsersMgrController : ControllerBase { private readonly UserDbContext dbCtx; private readonly UserDomainService domainService; - private readonly UserApplicationService appService; + private readonly IUserDomainRepository repository; - public UsersMgrController(UserDbContext dbCtx, UserDomainService domainService, UserApplicationService appService) + public UsersMgrController(UserDbContext dbCtx, UserDomainService domainService, IUserDomainRepository repository) { this.dbCtx = dbCtx; this.domainService = domainService; - this.appService = appService; + this.repository = repository; } [HttpPost] public async Task AddNew(PhoneNumber req) { - if ((await appService.FindOneAsync(req))!=null) + if ((await repository.FindOneAsync(req))!=null) { return BadRequest("手机号已经存在"); } @@ -36,7 +36,7 @@ public async Task AddNew(PhoneNumber req) [HttpPut] public async Task ChangePassword(ChangePasswordRequest req) { - var user = await appService.FindOneAsync(req.Id); + var user = await repository.FindOneAsync(req.Id); if(user == null) { return NotFound(); @@ -49,7 +49,7 @@ public async Task ChangePassword(ChangePasswordRequest req) [Route("{id}")] public async Task Unlock(Guid id) { - var user = await appService.FindOneAsync(id); + var user = await repository.FindOneAsync(id); if (user == null) { return NotFound(); diff --git "a/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/Users.WebAPI/Events/UserAccessResultEventHandler.cs" "b/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/Users.WebAPI/Events/UserAccessResultEventHandler.cs" index dedde5f..d9a61b7 100644 --- "a/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/Users.WebAPI/Events/UserAccessResultEventHandler.cs" +++ "b/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/Users.WebAPI/Events/UserAccessResultEventHandler.cs" @@ -1,4 +1,5 @@ using MediatR; +using Users.Domain; using Users.Domain.Events; namespace Users.WebAPI.Events @@ -6,11 +7,11 @@ namespace Users.WebAPI.Events public class UserAccessResultEventHandler : INotificationHandler { - private readonly UserApplicationService appService; + private readonly IUserDomainRepository repository; - public UserAccessResultEventHandler(UserApplicationService appService) + public UserAccessResultEventHandler(IUserDomainRepository repository) { - this.appService = appService; + this.repository = repository; } public Task Handle(UserAccessResultEvent notification, CancellationToken cancellationToken) @@ -38,7 +39,7 @@ public Task Handle(UserAccessResultEvent notification, CancellationToken cancell default: throw new NotImplementedException(); } - return appService.AddNewLoginHistoryAsync(phoneNum,msg); + return repository.AddNewLoginHistoryAsync(phoneNum,msg); } } } diff --git "a/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/Users.WebAPI/Program.cs" "b/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/Users.WebAPI/Program.cs" index 511dc59..8d81ae1 100644 --- "a/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/Users.WebAPI/Program.cs" +++ "b/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/Users.WebAPI/Program.cs" @@ -1,7 +1,6 @@ using MediatR; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.DependencyInjection; using System.Reflection; using Users.Domain; using Users.Infrastructure; @@ -30,7 +29,7 @@ }); builder.Services.AddScoped(); builder.Services.AddScoped(); -builder.Services.AddScoped(); +builder.Services.AddScoped(); builder.Services.AddMediatR(Assembly.GetExecutingAssembly()); var app = builder.Build(); // Configure the HTTP request pipeline. diff --git "a/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/Users.WebAPI/UnitOfWorkFilter.cs" "b/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/Users.WebAPI/UnitOfWorkFilter.cs" index e7975f2..7995891 100644 --- "a/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/Users.WebAPI/UnitOfWorkFilter.cs" +++ "b/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/Users.WebAPI/UnitOfWorkFilter.cs" @@ -8,14 +8,13 @@ namespace Users.WebAPI { public class UnitOfWorkFilter: IAsyncActionFilter - { - private IServiceProvider serviceProvider; - + { + //private IServiceProvider serviceProvider; + /* public UnitOfWorkFilter(IServiceProvider serviceProvider) { this.serviceProvider = serviceProvider; - } - + }*/ private static UnitOfWorkAttribute? GetUoWAttr(ActionDescriptor actionDesc) { var caDesc = actionDesc as ControllerActionDescriptor; @@ -51,7 +50,8 @@ public UnitOfWorkFilter(IServiceProvider serviceProvider) List dbCtxs = new List(); foreach (var dbCtxType in uowAttr.DbContextTypes) { - DbContext dbCtx = (DbContext)serviceProvider.GetRequiredService(dbCtxType); + var sp = context.HttpContext.RequestServices; + DbContext dbCtx = (DbContext)sp.GetRequiredService(dbCtxType); dbCtxs.Add(dbCtx); } var result = await next(); diff --git "a/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/Users.WebAPI/UserApplicationService.cs" "b/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/Users.WebAPI/UserApplicationService.cs" deleted file mode 100644 index 4721265..0000000 --- "a/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/\346\234\200\345\220\216\344\270\200\347\253\240\351\235\236\351\241\271\347\233\256\344\273\243\347\240\201/Users.WebAPI/UserApplicationService.cs" +++ /dev/null @@ -1,38 +0,0 @@ -using Microsoft.EntityFrameworkCore; -using Users.Domain; -using Users.Infrastructure; -using static Users.Infrastructure.ExpressionHelper; - -namespace Users.WebAPI -{ - public class UserApplicationService - { - private readonly UserDbContext dbCtx; - - public UserApplicationService(UserDbContext dbCtx) - { - this.dbCtx = dbCtx; - } - - public Task FindOneAsync(PhoneNumber phoneNumber) - { - ////if(dbCtx.Users.Any(u=>u.PhoneNumber.RegionCode==req.RegionCode&&u.PhoneNumber.Numbe - return dbCtx.Users.Include(u=>u.AccessFail).SingleOrDefaultAsync(MakeEqual((User u) => u.PhoneNumber, phoneNumber)); - } - - public Task FindOneAsync(Guid userId) - { - return dbCtx.Users.Include(u => u.AccessFail) - .SingleOrDefaultAsync(u=>u.Id==userId); - } - - public async Task AddNewLoginHistoryAsync(PhoneNumber phoneNumber,string msg) - { - var user = await FindOneAsync(phoneNumber); - UserLoginHistory history = new UserLoginHistory(user?.Id, - phoneNumber, msg); - dbCtx.LoginHistories.Add(history); - //这里不保存 - } - } -} diff --git "a/\346\234\200\345\220\216\345\244\247\351\241\271\347\233\256\344\273\243\347\240\201/YouZack-VNext/Zack.Infrastructure/EFCore/ExpressionHelper.cs" "b/\346\234\200\345\220\216\345\244\247\351\241\271\347\233\256\344\273\243\347\240\201/YouZack-VNext/Zack.Infrastructure/EFCore/ExpressionHelper.cs" index 7acd215..7069033 100644 --- "a/\346\234\200\345\220\216\345\244\247\351\241\271\347\233\256\344\273\243\347\240\201/YouZack-VNext/Zack.Infrastructure/EFCore/ExpressionHelper.cs" +++ "b/\346\234\200\345\220\216\345\244\247\351\241\271\347\233\256\344\273\243\347\240\201/YouZack-VNext/Zack.Infrastructure/EFCore/ExpressionHelper.cs" @@ -15,7 +15,9 @@ public class ExpressionHelper /// /// /// - public static Expression> MakeEqual(Expression> propAccessor, TProp other) + public static Expression> MakeEqual(Expression> propAccessor, TProp? other) + where TItem:class + where TProp:class { var e1 = propAccessor.Parameters.Single();//提取出来参数 BinaryExpression? conditionalExpr = null; @@ -23,7 +25,11 @@ public class ExpressionHelper { BinaryExpression equalExpr; //other的prop属性的值 - object? otherValue = prop.GetValue(other); + object? otherValue = null; + if(other!=null) + { + otherValue=prop.GetValue(other); + } Type propType = prop.PropertyType; //访问待比较的属性 var memAccessProp = MakeMemberAccess(