我正在浏览以下多个网站教程(https://app.pluralsight.com/library/courses/asp-dot-net-core-restful-api-building/table-of-contents) 并尝试将这些知识应用到我创建基础应用程序的现有数据库中。
1)我在AssetRepository的AddAsset开头设置了一个断点。
2)我将以下POST请求发送到我的API:
POST http://localhost:6059/api/assets
{
"bay": "X",
"tile": "1",
"Serialnumber": "SERIAL",
"devicename": "DEVICENAME",
"assetspecs" : [
{
"assetattrid": "SIZE",
"numvalue":12
},
{
"assetattrid": "POWER",
"numvalue":24
}
]
}
3)CreateAsset从AssetController运行,AddAsset从存储库通过控制器运行
4)调试器遇到_assetRepository.AddAsset(assetEntity)行;并从存储库中运行AddAsset
5)在执行AssetRepository.AddAsset的最后一行之前(_context.Asset.Add(asset);)调试器向我显示在进入行之前我有一组具有唯一ID的正确形式的记录 - 一切看起来都很好,并且应该将它添加到数据库中。
6)我点击了f11并且调试器跳转到我的上下文文件并运行OnConfiguring和OnModelCreating而没有任何问题然后返回到CreateAsset 控制器动作从中断。
7)我点击f11 AGAIN并检查if(!_assetRepository.Save())条件,该条件会抛出一个接受,告诉我有一个无效的列名Assetuid。在应用程序洞察调试输出中,列是大写的,所有其他列都以小写字母开头,看起来很奇怪。
我已经花了半天时间,如果有人可以提供帮助,我会感到茫然。还有一些可能涉及的文件我没有代表,如果你需要进一步查看,请告诉我,谢谢!!!!
aContext.cs
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.Extensions.Configuration;
namespace AssetAPI.Entities
{
public partial class aContext : DbContext
{
public aContext(DbContextOptions<aContext> options) : base(options)
{
}
public static IConfiguration Configuration;
public virtual DbSet<Asset> Asset { get; set; }
public virtual DbSet<Assetspec> Assetspec { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
optionsBuilder.UseSqlServer(Configuration["connectionStrings:AssetDBConnectionString"])
.EnableSensitiveDataLogging();
}
else
{
optionsBuilder.EnableSensitiveDataLogging();
}
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Asset>(entity =>
{
entity.HasKey(e => e.Assetuid)
.ForSqlServerIsClustered(false);
entity.ToTable("asset");
entity.HasIndex(e => e.Assetid)
.HasName("asset_indx7");
entity.HasIndex(e => e.Assetuid)
.HasName("asset_ndx")
.IsUnique();
entity.HasIndex(e => e.Barcode)
.HasName("asset_barcode");
entity.HasIndex(e => e.Pluscphyloc)
.HasName("asset_ndx16");
entity.HasIndex(e => e.Status)
.HasName("asset_ndx15");
entity.HasIndex(e => new { e.Assetnum, e.Assetuid })
.HasName("asset_ndx17");
entity.HasIndex(e => new { e.Assetnum, e.Siteid })
.HasName("asset_ndx11")
.IsUnique();
entity.HasIndex(e => new { e.Assetnum, e.Status })
.HasName("asset_ndx8");
entity.HasIndex(e => new { e.Orgid, e.Status })
.HasName("asset_ndx13");
entity.HasIndex(e => new { e.Siteid, e.Ancestor })
.HasName("asset_ndx7");
entity.HasIndex(e => new { e.Siteid, e.Assetnum })
.HasName("asset_ndx1")
.IsUnique()
.ForSqlServerIsClustered();
entity.HasIndex(e => new { e.Siteid, e.Calnum })
.HasName("asset_ndx4");
entity.HasIndex(e => new { e.Siteid, e.Location })
.HasName("asset_ndx6");
entity.HasIndex(e => new { e.Siteid, e.Parent })
.HasName("asset_ndx2");
entity.HasIndex(e => new { e.Siteid, e.Status })
.HasName("asset_ndx10");
entity.HasIndex(e => new { e.Siteid, e.Vendor })
.HasName("asset_ndx3");
entity.HasIndex(e => new { e.Assetid, e.Siteid, e.Moved })
.HasName("asset_ndx14")
.IsUnique();
entity.HasIndex(e => new { e.Assetnum, e.Location, e.Siteid })
.HasName("asset_ndx12");
entity.HasIndex(e => new { e.Itemnum, e.Siteid, e.Itemsetid })
.HasName("asset_ndx5");
entity.HasIndex(e => new { e.Siteid, e.Location, e.Parent })
.HasName("asset_ndx9");
entity.Property(e => e.Assetuid)
.HasColumnName("assetuid");
.ValueGeneratedNever();
..... Properties hidden, lots of them, came from scaffolding existing table
});
modelBuilder.Entity<Assetspec>(entity =>
{
entity.ToTable("assetspec");
entity.HasIndex(e => e.Assetspecid)
.HasName("assetspec_ndx")
.IsUnique();
entity.HasIndex(e => new { e.Assetattrid, e.Section })
.HasName("assetspec_ndx3");
entity.HasIndex(e => new { e.Assetnum, e.Siteid })
.HasName("assetspec_ndx4");
entity.HasIndex(e => new { e.Classstructureid, e.Assetattrid, e.Section })
.HasName("assetspec_ndx2");
entity.HasIndex(e => new { e.Assetattrid, e.Assetnum, e.Section, e.Siteid, e.Linearassetspecid })
.HasName("assetspec_ndx1")
.IsUnique();
entity.Property(e => e.Assetspecid)
.HasColumnName("assetspecid")
.ValueGeneratedNever();
... ..... Properties hidden, lots of them, came from scaffolding existing table
});
}
}
}
AssetRepository.cs
using System;
using System.Collections.Generic;
using System.Linq;
using AssetAPI.Entities;
namespace AssetAPI.Services
{
public class AssetRepository : IAssetRepository
{
private aContext _context;
public AssetRepository(aContext context)
{
_context = context;
}
public void AddAsset(Entities.Asset asset)
{
Random rnd = new Random();
asset.Assetid = rnd.Next(20000000, 30000000);
asset.Assetuid = rnd.Next(20000000, 30000000);
asset.Assetnum = rnd.Next(800000, 900000).ToString();
asset.Barcode = asset.Assetnum;
asset.Changedate = DateTime.Now;
asset.Changeby = "123";
asset.Langcode = "EN";
asset.Siteid = "SITE";
asset.Orgid = "ORG";
// the repository fills the id (instead of using identity columns)
if (asset.Assetspecs.Any())
{
foreach (var assetspec in asset.Assetspecs)
{
Random rnd2 = new Random();
assetspec.Assetspecid = rnd2.Next(20000000, 30000000);
assetspec.Changedate = DateTime.Today;
assetspec.Assetnum = asset.Assetnum;
assetspec.Classstructureid = "1140";
assetspec.Orgid = "ORG";
assetspec.Siteid = "SITE";
assetspec.Continuous = 0;
assetspec.Displaysequence = 0;
assetspec.Inheritedfromitem = 0;
assetspec.Itemspecvalchanged = 0;
assetspec.Mandatory = 0;
}
}
_context.Asset.Add(asset);
}
public void AddAssetspecForAsset(string assetnum, Assetspec assetspec)
{
var asset = GetAsset(assetnum);
if (asset != null)
{
assetspec.Assetnum = assetnum;
assetspec.Changeby = "123";
assetspec.Changedate = DateTime.Now;
assetspec.Classstructureid = "1140";
assetspec.Orgid = "ORG";
assetspec.Siteid = "SITE";
// if there isn't an id filled out (ie: we're not upserting),
// we should generate one
if (assetspec == null)
{
Random rnd2 = new Random();
assetspec.Assetspecid = rnd2.Next(20000000, 30000000);
assetspec.Assetattrid = "RUSZ";
assetspec.Numvalue = 12;
}
asset.Assetspecs.Add(assetspec);
}
}
public bool AssetExists(string assetnum)
{
return _context.Asset.Any(a => a.Assetnum == assetnum);
}
public Asset GetAsset(string assetnum)
{
return _context.Asset.FirstOrDefault(a => a.Assetnum == assetnum);
}
public IEnumerable<Entities.Asset> GetAssets()
{
// return _context.Asset.OrderBy(a => a.Barcode).ThenBy(a => a.Bay).ThenBy(a => a.Tile).Take(10).ToList();
return _context.Asset.OrderByDescending(a => a.Bay).ThenBy(a => a.Tile).Take(10).ToList();
}
public IEnumerable<Entities.Asset> GetAssets(IEnumerable<string> Assetnums)
{
return _context.Asset.Where(a => Assetnums.Contains(a.Assetnum))
.OrderBy(a => a.Barcode)
.OrderBy(a => a.Bay)
.OrderBy(a => a.Tile)
.ToList();
}
public IEnumerable<Assetspec> GetAssetspecsForAsset(string assetnum)
{
return _context.Assetspec
.Where(b => b.Assetnum == assetnum && b.Assetattrid == "RUSZ").OrderBy(b => b.Assetnum).ToList();
}
public bool Save()
{
return (_context.SaveChanges() >= 0);
}
public Assetspec GetAssetspecsForAsset(string assetnum, long assetspecId)
{
return _context.Assetspec
.Where(b => b.Assetnum == assetnum && b.Assetspecid == assetspecId).FirstOrDefault();
}
}
}
Asset.cs
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace AssetAPI.Entities
{
public partial class Asset
{
[Key]
public long Assetuid { get; set; }
public string Bay { get; set; }
public string Tile { get; set; }
public string TileLocation { get; set; }
public string Serialnumber { get; set; }
public string Devicename { get; set; }
....scaffolded properties hidden
public virtual ICollection<Assetspec> Assetspecs { get; set; } = new List<Assetspec>();
}
}
AssetsController.cs
using AssetAPI.Models;
using AssetAPI.Services;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using AutoMapper;
using AssetAPI.Entities;
namespace AssetAPI.Controllers
{
[Route("api/assets")]
public class AssetsController : Controller
{
private IAssetRepository _assetRepository;
public AssetsController(IAssetRepository assetRepository)
{
_assetRepository = assetRepository;
}
public IActionResult GetAssets()
{
var assetsFromRepo = _assetRepository.GetAssets();
var assets = Mapper.Map<IEnumerable<AssetDTO>>(assetsFromRepo);
return Ok(assets);
}
[HttpGet("{assetnum}", Name = "GetAsset")]
public IActionResult GetAsset(string assetnum)
{
var assetFromRepo = _assetRepository.GetAsset(assetnum); //Run GetAsset method for the passed in Assetid from AssetRepository
if (assetFromRepo == null)
{
return NotFound();
}
var asset = Mapper.Map<AssetDTO>(assetFromRepo); //Map the entity to the DTO
return Ok(asset); //Return the result in JSON format
}
//[FromBody] attribute signifies that parameter should be serialized from the request body into AssetForCreationDTO
[HttpPost]
public IActionResult CreateAsset([FromBody] AssetForCreationDTO asset)
{
//If the input provider in the request body was correctly serialized to an AssetForCreationDTO
if (asset == null)
{
return BadRequest();
}
var assetEntity = Mapper.Map<Asset>(asset); //Map the entity to the DTO
_assetRepository.AddAsset(assetEntity); //Add the entity to the DBContext
if (!_assetRepository.Save()) //If the new resource cannot be saved
{
throw new Exception("Creating asset failed upon save");
return StatusCode(500, "A problem occured.");
}
//Map the results again to learn the ID of the newly created resource
var assetToReturn = Mapper.Map<AssetDTO>(assetEntity);
//In case of a successful post, return 201 created response with location header
//First param = name of route
//Second = anon type containing new resource id
//Third = Response body of newly created resource
return CreatedAtRoute("GetAsset", new { assetnum = assetToReturn.assetnum }, assetToReturn);
}
}
}
AssetDTO.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace AssetAPI.Models
{
public class AssetDTO
{
public string assetnum { get; set; }
public string Barcode { get; set; }
public string Bay { get; set; }
public string Tile { get; set; }
public string TileLocation { get; set; }
public string Serialnumber { get; set; }
public string Devicename { get; set; }
}
}
AssetForCreationDTO:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace AssetAPI.Models
{
public class AssetForCreationDTO
{
public string Bay { get; set; }
public string Tile { get; set; }
public string TileLocation { get; set; }
public string Serialnumber { get; set; }
public string Devicename { get; set; }
public ICollection<AssetspecForCreationDTO> Assetspecs { get; set; } = new List<AssetspecForCreationDTO>();
}
}
答案 0 :(得分:1)
解决了我的问题。
由于此代码背后的应用程序使用表格并且我将ASSETUID错误地设置为关键字段,因此我没有像EFcore那样强制执行关系。
由于assetspec实体没有ASSETUID列,根据我所做的一些研究,这会导致导航属性出现问题。
我将PK改为ASSETNUM;既然两个实体都有ASSETNUM作为财产,我现在都很好!