abp-vnext-pro 實戰(八,聚合根的寫法,客戶M:N地址)

參考數據字典模塊的寫法

/// <summary>
/// 地址
/// </summary>
public class Address : FullAuditedAggregateRoot<Guid>,IMultiTenant
{

    public Guid? TenantId { get; protected set; }

    /// <summary>
    /// 公司名
    /// </summary>
    public string Company { get; private set; }
    /// <summary>
    /// 城市
    /// </summary>
    public string City { get; private set; }
    /// <summary>
    /// 地址
    /// </summary>
    public string Address1 { get; private set; }
    /// <summary>
    /// 郵編
    /// </summary>
    public string ZipPostalCode { get; private set; }
    /// <summary>
    /// 電話
    /// </summary>
    public string PhoneNumber { get; private set; }

    public List<Customer> Customers { get; private set; }  


}

public class Customer : FullAuditedAggregateRoot<Guid>, IMultiTenant
{

    public Guid? TenantId { get; protected set; }
    /// <summary>
    /// 客戶名字
    /// </summary>
    public string Name { get; private set; }
    /// <summary>
    /// 客戶編號
    /// </summary>
    public string Code { get; private set; }
    /// <summary>
    /// 客戶簡稱
    /// </summary>
    public string ShortName { get; private set; }
    /// <summary>
    /// 組織代碼
    /// </summary>
    public string OrgCode { get; private set; }


    public List<Address> CustAddresses { get; private set; }
}

application.contract 項目裏的PageAddressInput,增加一個客戶字段custId用於查詢關聯, nswag/refresh.bat 要執行刷新。

public class PageAddressInput: PagingBase
{
    public Guid CustId { get; set; }
}

 對應的CreateAddressInput 也要加一個CustId的字段,而更新地址時不需要改變CustId

 

EntityFrameworkCore 項目裏 ERPDbContextModelCreatingExtensions 多對多的默認寫法

                b.HasMany(b => b.CustAddresses).WithMany(c=>c.Customers)
                .UsingEntity("CustAddresses");

對應生成的數據庫結構是這樣

            migrationBuilder.CreateTable(
                name: "CustAddresses",
                columns: table => new
                {
                    CustAddressesId = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"),
                    CustomersId = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci")
                },
                constraints: table =>
                {
                    table.PrimaryKey("PK_CustAddresses", x => new { x.CustAddressesId, x.CustomersId });
                    table.ForeignKey(
                        name: "FK_CustAddresses_CrmAddresses_CustAddressesId",
                        column: x => x.CustAddressesId,
                        principalTable: "CrmAddresses",
                        principalColumn: "Id",
                        onDelete: ReferentialAction.Cascade);
                    table.ForeignKey(
                        name: "FK_CustAddresses_CrmCustomer_CustomersId",
                        column: x => x.CustomersId,
                        principalTable: "CrmCustomer",
                        principalColumn: "Id",
                        onDelete: ReferentialAction.Cascade);
                })
                .Annotation("MySql:CharSet", "utf8mb4");

            migrationBuilder.CreateIndex(
                name: "IX_CustAddresses_CustomersId",
                table: "CustAddresses",
                column: "CustomersId");

 假如要指定中間表的字段名,則2個對象都要指定

 builder.Entity<Customer>(b =>
            {
                b.ToTable(ERPConsts.CRMDbTablePrefix + "Customer", ERPConsts.DbSchema);
                b.ConfigureByConvention(); 
                b.HasMany(b => b.CustAddresses).WithMany(c=>c.Customers)
                .UsingEntity("CustAddresses",
                l => l.HasOne(typeof(Customer)).WithMany().HasForeignKey("Customer_Id").HasPrincipalKey(nameof(Customer.Id)),
                r => r.HasOne(typeof(Address)).WithMany().HasForeignKey("Address_Id").HasPrincipalKey(nameof(Address.Id)),
                j => j.HasKey("Customer_Id", "Address_Id"));

                //The skip navigation 'Address.Customers' doesn't have a foreign key associated with it.
                //Every skip navigation must have a configured foreign key.
            });

            builder.Entity<Address>(b =>
            {
                //b.ToTable(ERPConsts.CRMDbTablePrefix + nameof(Address).Pluralize
                b.ToTable(ERPConsts.CRMDbTablePrefix + "Addresses");

                b.ConfigureByConvention();
                b.HasMany(b => b.Customers).WithMany(c => c.CustAddresses)
                .UsingEntity("CustAddresses",
                l => l.HasOne(typeof(Customer)).WithMany().HasForeignKey("Customer_Id").HasPrincipalKey(nameof(Customer.Id)),
                r => r.HasOne(typeof(Address)).WithMany().HasForeignKey("Address_Id").HasPrincipalKey(nameof(Address.Id)),
                j => j.HasKey("Customer_Id", "Address_Id"));
            });

 

=======================================多對多前端頁面=============================

客戶列表界面A,點擊地址按鈕,新開一個tab頁面B,顯示該客戶下面的地址列表。

A頁面path= setting 的某個鏈接或按鈕,按下新開tab 頁面

1. 先在router/module裏定義一個隱藏菜單,path是 preViewCode

 {
      path: 'preViewCode',
      name: 'PreViewCode',
      component: () => import('/@/views/generators/PreViewCode.vue'),
      meta: {
        title: '預覽',
        icon: 'ant-design:file-sync-outlined',
        hideMenu: true,
      },

2. A頁面index.vue裏面 click事件裏用router.push傳path和參數

<a-button class="!ml-4" type="primary" @click="addTabPage">預覽</a-button>  

A頁面要引入 useRouter 

import { useRouter } from 'vue-router';

setup() {
const router = useRouter();

}

      //跳轉到地址列表頁,並傳遞客戶ID
      async function addTabPage(record: Recordable) {
        try {
          await router.push({
            name: 'AddressPage',
            query: { custId: record.id },
          });
        } catch (error) { }
      }

3. 再在B頁面的index.vue 頁面, 引入useRoute ,而不是useRouter, 差一個字母,很容易看錯

  import { useRoute } from 'vue-router';
  setup() {
      const route = useRoute();
      const queryParams = route.query;
      console.log(queryParams.custId);

      // table配置
      const [registerTable, { reload }] = useTable({
        columns: tableColumns,
        formConfig: {
          labelWidth: 70,
          schemas: searchFormSchema,
        },
        api: pageAsync11,  //



       function pageAsync11(a : any) {
         console.log("queryParams.custId傳到params: PageAddressInput");
        //params: any
        a.custId=queryParams.custId;
        return pageAsync(a);
      }

Domain 項目的 AddressManager

   private readonly IAddressRepository _addressRepository;
    private readonly ICustomerRepository _customerRepository;
    private readonly IObjectMapper _objectMapper;

    public AddressManager(IAddressRepository addressRepository, IObjectMapper objectMapper, ICustomerRepository customerRepository)
    {
        _addressRepository = addressRepository;
        _objectMapper = objectMapper;
        _customerRepository = customerRepository;
    }
    public async Task<List<AddressDto>> GetListAsync(Guid custId,int maxResultCount = 10, int skipCount = 0)
    {
        var list = await _customerRepository.GetCustAddressListAsync(custId, maxResultCount, skipCount);
        //var list = await _addressRepository.GetListAsync(maxResultCount, skipCount);
        return _objectMapper.Map<List<Address>, List<AddressDto>>(list);
    }

    /// <summary>
    /// 創建地址
    /// </summary>
    public async Task<AddressDto> CreateAsync(
        Guid id,
        int countryId,
        int stateProvinceId,
        string firstName,
        string lastName,
        string email,
        string company,
        string city,
        string address1,
        string zipPostalCode,
        string phoneNumber,
        Guid custId
    )
    {
        var entity = new Address(id, countryId, stateProvinceId, firstName, lastName, email, company, city, address1, zipPostalCode, phoneNumber);
        entity = await _addressRepository.InsertAsync(entity);
        //客戶地址增加關聯
        var cust = await _customerRepository.GetAsync(custId);
        cust.AddAddress(entity);
        return _objectMapper.Map<Address, AddressDto>(entity);
    }

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章