我正在尝试保存Firm
包含地址和网站的对象。我开发了在 Angular 7 中使用反应式表单在 UI 中添加和删除地址控件的功能。Firm
对象,它正在为地址和网站创建附加条目,而不是将其视为现有记录。
因此,如果我从 UI 中删除网站和地址,我可以看到我正在将正确数量的数组元素传递给后端 api。所以我确信问题出在实体框架上。
所以我想要实现的是,如果用户从客户端删除地址或网站,则在调用实体框架中的更新方法时应该更新相同的地址或网站。我正在使用实体框架 6
UI - 我可以在其中添加多个地址
这是我的模型类
新公司视图模型
public class NewFirmViewModel
{
public int FirmId { get; set; }
public string FirmName { get; set;}
public Nullable<DateTime> DateFounded { get; set; }
public ICollection<AddressViewModel> Addresses { get; set; }
public ICollection<WebsiteViewModel> Websites { get; set; }
public bool hasIntralinks { get; set; }
}
地址视图模型
public class AddressViewModel
{
public int AddressId { get; set; }
public string Line1 { get; set; }
public string Line2 { get; set; }
public string Line3 { get; set; }
public string Phone { get; set; }
public bool IsHeadOffice { get; set; }
public int FirmId { get; set; }
}
网站视图模型
public class WebsiteViewModel
{
private int FirmWebsiteId { get; set; }
private string WebsiteUrl { get; set; }
public string Username { get; set; }
public string Password { get; set; }
public int FirmId { get; set; }
}
Entities
public class FIRM: Entity,IHasAUMs<FIRM_AUM>
{
public FIRM()
{
//this.FIRM_PERSON = new HashSet<FIRM_PERSON>();
this.MANAGERSTRATEGies = new HashSet<MANAGERSTRATEGY>();
this.FIRM_ACTIVITY = new HashSet<FIRM_ACTIVITY>();
this.FIRM_AUMs = new HashSet<FIRM_AUM>();
this.FIRM_REGISTRATION = new HashSet<FIRM_REGISTRATION>();
//this.ACTIVITies = new HashSet<ACTIVITY>();
Addresses = new HashSet<ADDRESS>();
//People = new HashSet<PERSON>();
// Websites = new HashSet<FIRM_WEBSITE>();
}
//public decimal ID { get; set; }
//
//
//
//
public string NAME { get; set; }
public string SHORT_NAME { get; set; }
public string ALTERNATE_NAME { get; set; }
public string WEBSITE { get; set; }
public string WEBSITE_USERNAME { get; set; }
public string WEBSITE_PASSWORD { get; set; }
public bool? INTRALINKS_FIRM { get; set; }
public string NOTES_TEXT { get; set; }
public string NOTES_HTML { get; set; }
public string HISTORY_TEXT { get; set; }
public string HISTORY_HTML { get; set; }
public string HISTORY_SUM_TEXT { get; set; }
public string HISTORY_SUM_HTML { get; set; }
public Nullable<decimal> OLD_ORG_REF { get; set; }
public Nullable<decimal> SOURCE_ID { get; set; }
[DisplayFormat(DataFormatString = PermalConstants.DateFormat)]
public Nullable<DateTime> DATE_FOUNDED { get; set; }
public virtual ICollection<ADDRESS> Addresses { get; set; }
// public ICollection<FIRM_WEBSITE> Websites { get; set; }
// public ICollection<PERSON> People { get; set; }
//public SOURCE SOURCE { get; set; }
// public ICollection<FIRM_PERSON> FIRM_PERSON { get; set; }
public ICollection<MANAGERSTRATEGY> MANAGERSTRATEGies { get; set; }
public ICollection<FIRM_ACTIVITY> FIRM_ACTIVITY { get; set; }
public ICollection<FIRM_REGISTRATION> FIRM_REGISTRATION { get; set; }
//public ICollection<ACTIVITY> ACTIVITies { get; set; }
public ICollection<FIRM_WEBSITE> Websites { get; set; }
public Nullable<int> KEY_CONTACT_ID { get; set; }
[NotMapped]
public ICollection<FIRM_AUM> AUMs
{
get
{
return this.FIRM_AUMs;
}
}
public ICollection<FIRM_AUM> FIRM_AUMs { get; set; }
}
ADDRESS
public class ADDRESS : Entity
{
public ADDRESS()
{
// DATE_CREATED = DateTime.Now;
}
public string LINE1 { get; set; }
public string LINE2 { get; set; }
public string LINE3 { get; set; }
public int CITY_ID { get; set; }
public string POSTAL_CODE { get; set; }
public string SWITCHBOARD_INT { get; set; }
public string NOTES { get; set; }
public int? OLD_ADDRESS_REF { get; set; }
public int? SOURCE_ID { get; set; }
public int FIRM_ID { get; set; }
[ForeignKey("FIRM_ID")]
public FIRM FIRM { get; set; }
[ForeignKey("CITY_ID")]
public CITY City { get; set; }
public ICollection<PERSON> People { get; set; }
// public SOURCE SOURCE { get; set; }
public bool IS_HEAD_OFFICE { get; set; }
[NotMapped]
public string AddressBlurb
{
get
{
return string.Join(",", new[] { LINE1, LINE2, City != null ? City.NAME : "", City != null && City.Country != null ? City.Country.NAME : "" }.Where(x => !string.IsNullOrEmpty(x)));
}
}
}
FIRM_WEBSITE
public class FIRM_WEBSITE : Entity
{
public FIRM_WEBSITE()
{
}
private string _WEBSITE_URL;
public string WEBSITE_URL
{
get
{
if (string.IsNullOrEmpty(_WEBSITE_URL))
return _WEBSITE_URL;
try
{
var ubuilder = new System.UriBuilder(_WEBSITE_URL ?? "");
return ubuilder.Uri.AbsoluteUri;
}
catch (UriFormatException ex)
{
return _WEBSITE_URL;
}
}
set { _WEBSITE_URL = value; }
}
public string USERNAME { get; set; }
public string PASSWORD { get; set; }
public int FIRM_ID { get; set; }
[ForeignKey("FIRM_ID")]
public FIRM FIRM { get; set; }
}
API控制器
[HttpPut]
[SkipTokenAuthorization]
[Route("api/firm/update")]
public IHttpActionResult Update(NewFirmViewModel model)
{
var firmService = GetService<FIRM>();
if (model == null) return StatusCode(HttpStatusCode.NotFound);
var firm = firmService.GetWithIncludes(model.FirmId);
if (firm != null)
{
firm.NAME = model.FirmName;
firm.DATE_FOUNDED = model.DateFounded;
firm.Addresses = model.Addresses.Select(x => new ADDRESS() {ID = x.AddressId, LINE1 = x.Line1, LINE2 = x.Line2, LINE3 = x.Line3, FIRM_ID = x.FirmId}).ToList();
firm.Websites = model.Websites.Select(x => new FIRM_WEBSITE() {ID = x.FirmWebsiteId, WEBSITE_URL = x.WebsiteUrl, USERNAME = x.Username, PASSWORD = x.Password, FIRM_ID = x.FirmId}).ToList();
var addressIds = model.Addresses.Select(x => x.AddressId).ToList();
var addresses = firm.Addresses.Where(x => addressIds.Contains(x.ID)).ToList(); // All of the addresses we want to associate to this firm.
// Identify addresses to remove from this firm.
var addressesToRemove = firm.Addresses.Where(x => !addressIds.Contains(x.ID)).ToList();
foreach (var address in addressesToRemove)
firm.Addresses.Remove(address);
// Identify addresses to associate to this firm.
var existingAddressIds = firm.Addresses.Select(x => x.ID).ToList();
var addressesToAdd = addresses.Where(x => !existingAddressIds.Contains(x.ID)).ToList();
foreach (var address in addressesToAdd)
firm.Addresses.Add(address);
firmService.Update(firm);
}
else
{
}
return Ok(firm);
}
数据库上下文
public class Repo<T> : IRepo<T> where T : Entity, new()
{
public readonly Db dbContext;
private ILogger _logger;
private IQueryable<T> lastQuery { get; set; }
private bool? _enablelazyloading;
private IEntityWatcher<T> _watcherNotification;
private bool _EnableChangeNotification;
public string ID { get; set; }
private string _clientId;
#region Constructors
public Repo(IDbContextFactory f)
{
if (typeof(T).GetCustomAttribute<SeparateDbContext>() != null)
dbContext = f.GetContext<T>();
else
dbContext = f.GetContext();
_logger = IoC.Resolve<ILogger>();
try
{
_watcherNotification = IoC.Resolve<IEntityWatcher<T>>();
}
catch (Exception ex)
{
_logger.Error("Change Notification failed to resolve in Repo. The Repo will continue to function without notification.", ex);
}
}
public Repo() : this(new DbContextFactory()) { }
#endregion
public bool? EnableLazyLoading
{
get { return dbContext.EnableLazyLoading; }
set { dbContext.EnableLazyLoading = value; }
}
public void SetClientId(string clientId)
{
var oc = dbContext.Database.Connection as OracleConnection;
if (oc != null)
{
oc.Open();
oc.ClientId = clientId;
oc.Close();
}
}
public T Update(T obj)
{
_logger.Info("Repo.Update {0}", obj);
var entity = Get(obj.ID);
var oldEntity = new T();
var entry = dbContext.Entry(entity);
oldEntity.InjectFrom(entry.OriginalValues.ToObject());
if (dbContext.Entry(obj).State == System.Data.Entity.EntityState.Detached)
{
entry.CurrentValues.SetValues(obj);
}
LogAllModifiedEntities(dbContext);
dbContext.SaveChanges();
if (_watcherNotification != null)
_watcherNotification.EntityChanged(ChangeNotificationType.Modified, entity, oldEntity);
return Get(obj.ID);
}
public void EntityChanged(ChangeNotificationType changeNotificationType, T newEntity, T oldEntity) {
if(_entityAuditEnabled) {
var filter = IoC.Resolve<IEntityWatchFilter<T>>();
filter.Filter(changeNotificationType, newEntity, oldEntity);
}
}
}
public bool Filter(ChangeNotificationType changeNotificationType, T newEntity, T oldEntity) {
try {
///only
if(_WatchList.Contains(typeof(T).Name) || !_WatchList.Any()) {
var newLegacyStratImpl = newEntity as ILegacyStrategy;
var oldLegacyStratImpl = oldEntity as ILegacyStrategy;
var blankStrategies = IoC.Resolve<ICrudService<LEGACY_STRATEGY>>().Where(x => x.NAME.Trim() == "").Select(x => x.ID).AsEnumerable();
if(changeNotificationType == ChangeNotificationType.Added && newLegacyStratImpl != null && newLegacyStratImpl.LEGACY_STRATEGY_ID.HasValue && !blankStrategies.Contains(newLegacyStratImpl.LEGACY_STRATEGY_ID.Value)) {
_action.Added(newEntity);
return true;
} else if(changeNotificationType == ChangeNotificationType.Deleted && newLegacyStratImpl != null) {
_action.Deleted(newEntity);
return true;
} else if(changeNotificationType == ChangeNotificationType.Modified && newLegacyStratImpl != null && oldLegacyStratImpl != null) {
///need to go the extra distance and make sure the legacy strategy was changed and not some other property.
var hasChanged = newLegacyStratImpl.LEGACY_STRATEGY_ID != oldLegacyStratImpl.LEGACY_STRATEGY_ID;
if(hasChanged) {
_action.Modified(newEntity, oldEntity);
return true;
} else {
return false;
}
}
}
return false;///all else fails...
} catch(Exception ex) {
_logger.Error(ex);
return false;
}
}