Having issues with a dependent property in a referential restraint - c#

I keep getting this error when I try to submit to the database:
A dependent property in a ReferentialConstraint is mapped to a store-generated column. Column: 'NPPRProvId'
Here's where it breaks:
public static bool Save(NPPR_Provider provider, State state, string filename, bool validateBeforeSave = true )
{
using (var db = new NPPRContext(state))
{
var prov = new NPPR_Provider()
{
First = provider.First,
Middle = provider.Middle,
Last = provider.Last,
DateOfBirth = provider.DateOfBirth,
DateOfDeath = provider.DateOfDeath,
Gender = provider.Gender,
SSN = provider.SSN,
DegreeCode = provider.DegreeCode,
BusinessName = provider.BusinessName,
DbaName = provider.DbaName,
Action = "A",
EffectiveDate = "20121212",
EndDate = "99991231",
NPPR_ServLocation = new NPPR_ServLocation()
{
EnrollmentType = provider.NPPR_ServLocation.EnrollmentType,
OrganizationType = provider.NPPR_ServLocation.OrganizationType,
ProviderTypeCode = provider.NPPR_ServLocation.ProviderTypeCode,
IRSTaxAssociations = provider.NPPR_ServLocation.IRSTaxAssociations,
NPIAssociations = provider.NPPR_ServLocation.NPIAssociations,
Address = provider.NPPR_ServLocation.Address
},
NPPR_Header = new NPPR_Header()
{
FileName = filename,
TransactionDate = Utilities.DateTimeToPRNDate(DateTime.Now),
FileLoadDate = DateTime.Now,
SubmitterId = "M00000503",
Purpose = "A",
Action = "A"
}
};
foreach(var npi in prov.NPPR_ServLocation.NPIAssociations)
{
npi.NPIType = prov.NPPR_ServLocation.OrganizationType == "I" ? "1" : "2";
}
prov.NPPR_ServLocation.Licenses = SegmentOrNull<NPPR_Licenses>(provider.NPPR_ServLocation, "Licenses", "LicenseNumber");
prov.NPPR_ServLocation.Certifications = SegmentOrNull<NPPR_Certifications>(provider.NPPR_ServLocation, "Certifications", "CertificationNumber");
prov.NPPR_ServLocation.Specialties = SegmentOrNull<NPPR_Specialties>(provider.NPPR_ServLocation, "Specialties", "SpecialtyCode");
prov.NPPR_ServLocation.Taxonomies = SegmentOrNull<NPPR_Taxonomies>(provider.NPPR_ServLocation, "Taxonomies", "TaxonomyCode");
prov.NPPR_ServLocation.OtherIds = SegmentOrNull<NPPR_OtherIds>(provider.NPPR_ServLocation, "OtherIds", "IdentifierTypeId");
prov.NPPR_ServLocation.GroupAssociations = SegmentOrNull<NPPR_GroupAssociations>(provider.NPPR_ServLocation, "GroupAssociations", "ProviderLocationId");
db.NPPR_Provider.Add(prov);
if (validateBeforeSave)
db.SaveChangesWithValidation();
else
db.SaveChanges();
return true;
}
}
db.SaveChanges() is where, according to the stacktrace, the exception is thrown. This function was originally written for EF Core, but due to issues with the server, I was forced to turn everything to EF6.4. Under Core, this method worked fine, but under EF6, it throws an exception. I've tried a few things I've read on other SO questions but so far no luck.
Specifically the exception throws on the NPPR_Provider primary key, NPPRProvId, which at no point in my code is ever read or written, except to be defined in the model.
In SQL, the NPPRProvId is PK, int, not null
The model involved:
public class NPPR_Provider : Provider
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int NPPRProvId { get; set; }
//[ForeignKey("NPPR_Header")]
public int? NPPRFileId { get; set; }
[ForeignKey("NPPRFileId")]
public NPPR_Header NPPR_Header { get; set; }
[ForeignKey("NPPRProvId")]
public NPPR_ServLocation NPPR_ServLocation { get; set; }
}
What am I doing wrong here and how might I fix it? I'm still fairly new to EF and this is my first major project in EF and MVC, and in the .NET framework in general.

In EF Core the NPPR_ServLocation could be an owned object but to my knowledge in EF 6 there are not owned objects; you need to define them explicitly in a separate table and give them keys.
public class NPPR_Provider : Provider
{
public int NPPR_ProviderId { get; set; }
public NPPR_Header NPPR_Header { get; set; }
public NPPR_ServLocation NPPR_ServLocation { get; set; }
… // data properties here
}
public class NPPR_Header {
public int NPPR_HeaderId {get;set;}
public int NPPR_ProviderId {get;set;}
public NPPR_Provider {get;set;}
… // data properties here
}
public class NPPR_ServLocation {
public int NPPR_ServLocationId {get;set;}
public int NPPR_ProviderId {get;set;}
public NPPR_Provider {get;set;}
… // data properties here.
}

Related

DynamoDB - How to implement Optimistic Locking using ServiceStack.Aws

Currently, I am using ServiceStack.Aws v5.9.0 to communicate with DynamoDB. I have used PutItem for both creating and updating an item without anticipating data loss in case of concurrency handling.
public class Customer
{
[HashKey]
public int CustomerId { get; set; }
[AutoIncrement]
public int SubId { get; set; }
public string CustomerType { get; set; }
public string LastName { get; set; }
public string FirstName { get; set; }
...//and hundreds of fields here
}
public class CustomerDynamo
{
private readonly IPocoDynamo db;
//Constructor
public CustomerDynamo()
{
var dynamoClient = new AmazonDynamoDBClient(_region);
var entityType = typeof(Customer);
var tableName = entityType.Name;
entityType.AddAttributes(new AliasAttribute(name: tableName));
db = new PocoDynamo(dynamoClient) { ConsistentRead = true }.RegisterTable(tableType: entityType);
}
public Customer Update(Customer customer)
{
customer.ModifiedDate = DateTime.UtcNow;
db.PutItem(customer);
return customer;
}
}
The above Update method is called in every service/async task that needs to update the data of the customer.
Refer to this article of AWS I decided to implement the Optimistic Locking to save my life from the issue of concurrency requests.
https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBContext.VersionSupport.html
Assume that the VersionNumber will be the key for Optimistic Locking. So I added the VersionNumber into the Customer model.
public class Customer
{
[HashKey]
public int CustomerId { get; set; }
[AutoIncrement]
public int SubId { get; set; }
public string CustomerType { get; set; }
public string LastName { get; set; }
public string FirstName { get; set; }
...//and hundreds of fields here
[DynamoDBVersion]
public int? VersionNumber { get; set; }
}
The result is VersionNumber not updated while it should be automatically incremented. I think it is just because the PutItem will override the whole existing item. Is this correct?
I think I need to change from PutItem to UpdateItem in the Update method. The question is how can I generate the expression dynamically to be used with the UpdateItem?
Thanks in advance for any help!
Updates:
Thanks #mythz for the useful information about DynamoDBVersion attribute. Then I tried to remove the DynamoDBVersion and using the UpdateExpression of PocoDynamo as below
public Customer Update(Customer customer)
{
customer.ModifiedDate = DateTime.UtcNow;
var expression = db.UpdateExpression<Customer>(customer.CustomerId).Set(() => customer);
expression.ExpressionAttributeNames = new Dictionary<string, string>()
{
{ "#Version", "VersionNumber" }
};
expression.ExpressionAttributeValues = new Dictionary<string, AttributeValue>()
{
{ ":incr", new AttributeValue { N = "1" } },
{ ":zero", new AttributeValue { N = "0" } }
};
expression.UpdateExpression = "SET #Version = if_not_exists(#Version, :zero) + :incr";
if (customer.VersionNumber.HasValue)
{
expression.Condition(c => c.VersionNumber == customer.VersionNumber);
}
var success = db.UpdateItem(expression);
}
But the changes are not saved except the VersionNumber
The [DynamoDBVersion] is an AWS Object Persistence Model attribute for usage with AWS's DynamoDBContext not for PocoDynamo. i.e. the only [DynamoDB*] attributes PocoDynamo utilizes are [DynamoDBHashKey] and [DynamoDBRangeKey] all other [DynamoDB*] attributes are intended for AWS's Object Persistence Model libraries.
When needed you can access AWS's IAmazonDynamoDB with:
var db = new PocoDynamo(awsDb);
var awsDb = db.DynamoDb;
Here are docs on PocoDynamo's UpdateItem APIs that may be relevant.

Can't insert entity with foreign key in Entity Framework

I'm building Backend for Mobile Application with ASP.NET MVC Framework.
I have two Objects:
public class CarLogItem : EntityData
{
public CarLogItem(): base()
{
Time = DateTime.Now;
}
public DateTime Time { get; set; }
public int RPM { get; set; }
public int Speed { get; set; }
public int RunTime { get; set; }
public int Distance { get; set; }
public int Throttle { get; set; }
[ForeignKey("Trip")]
public String Trip_id { get; set; }
// Navigation property
public TripItem Trip { get; set; }
}
and
public class TripItem : EntityData
{
public TripItem() : base()
{
UserId = User.GetUserSid();
StartTime = DateTime.Now;
logItems = new List<CarLogItem>();
}
public string UserId { get; set; }
public List<CarLogItem> logItems {get;set;}
public DateTime StartTime { get; set; }
}
and I have controller, which add new CarLogItem to database.
public class CarLogItemController : TableController<CarLogItem>
{
// POST tables/CarLogItem
public async Task<IHttpActionResult> PostCarLogItem(CarLogItem item)
{
var lastItem = db.CarLogItems.OrderByDescending(x => x.Time).FirstOrDefault();
//lastItem = (Query().Where(logitem => true).OrderBy(logitem => logitem.Time)).Last();
//checking if lastItem.Trip isn't null because
// I have entities with Trip field is null, but all of them should have it.
if (lastItem != null && lastItem.Trip != null && item.RunTime > lastItem.RunTime)
{
item.Trip = lastItem.Trip;
}
//In order to test adding of new TripItem entity to database
// I compare item.RunTime with 120, so it always true
else if (lastItem == null || item.RunTime < 120) // < lastItem.RunTime)
{
var newTrip = new TripItem();
item.Trip = newTrip;
}
else
{
throw new ArgumentException();
}
CarLogItem current = await InsertAsync(item);
return CreatedAtRoute("Tables", new { id = current.Id }, current);
}
}
When I'm trying to add new CarLogItem with Trip = null it's ok, but when Trip is particular object it fails with following Exception:
The entity submitted was invalid: Validation error on property 'Id': The Id field is required
How properly to add new CarLogItem with nested TripItem?
I think that you need to populate the Id property on your TripItem, e.g.
var newTrip = new TripItem(){ Id = Guid.NewGuid() }
You need a primary key field in every entity class, like Id or CarLogItemId (ClassName + "Id"). Or just have a property with [Key] attribute:
[Key]
public string/int/Guid/any-db-supported-type MyProp { get; set; }
Entity Framework relies on every entity having a key value that it
uses for tracking entities. One of the conventions that code first
depends on is how it implies which property is the key in each of the
code first classes. That convention is to look for a property named
“Id” or one that combines the class name and “Id”, such as “BlogId”.
The property will map to a primary key column in the database.
Please see this for more details.
I also suspect this to be a problem:
public Lazy<CarLogItem> logItems { get; set; }
You don't have to mark navigation property as Lazy<>. It is already lazy (unless you have configuration that disables lazy loading). Please try to remove Lazy<> and see if it works this way.

Update Unique property entity framework

public class Person
{
[Required]
public int? KupaId { get; set; }
[ForeignKey("KupaId")]
public Kupa Kupa { get; set; }
public int? newKupaId { get; set; }
[ForeignKey("newKupaId")]
public Kupa NewKupa { get; set; }
}
public class Kupa
{
public int Id { get; set; }
[Index("Ix_uniqueId", IsUnique = true)]
public int ? uniqueId { get; set; }
}
public class MyController:Controller
{
public Json EditKupa(Expression<Func<Person,bool>> criteria )
{
using (IKupotRepository<Person> _IPersonRepository = new SQlRepository<Person>())
{
Person personToEdit=_IPersonRepository.SingleOrDefault(criteria,GetIncludeProperties());
> //Getting the new kupa obj from db
newKupa = GetKupa(UniqueId);
<//changing the unique property to null
personToEdit.Kupa.ToremId = null;
personToEdit.Kupa.State = State.Modified;
personToEdit.NewKupa = newKupa;
>//Assign the unique id property the value that was in the first Kupa
personToEdit.NewKupa.ToremId = 1;
personToEdit.newKupaId = newKupa.Id;
personToEdit.NewKupa.State = State.Modified;
_IPersonRepository.SaveChanges();
}
}
when calling saveChanges() getting an exception :unique key violation , when looking at the sql profiler i can see that EF 6 generates an update query for both the Kupa object but it tries to update the NewKupa.uniqueId before updating the Kupa.uniqueId ?
Assuming you are using SQL Server as a database server this is happening because you allow NULL values in that column and NULL = NULL is NULL so if you have multiple rows with NULL on that column you'll get the error.
To implement this in SQL statements will be like this:
CREATE UNIQUE NONCLUSTERED INDEX Idx_UniqueId_NotNull
ON Kupa(uniqueId)
WHERE uniqueId IS NOT NULL;
However, to do this in EF there is no easy way, but there is a workaround in this SO answer here.

Saving primary and foreign keytables at once in EF6

I have primary table and 3 foreign key tables and trying to save all at once. Some time some OK and some time giving error.
public partial class meeting_abstract
{
public int meeting_abstract_id { get; set; }
public int meeting_id { get; set; }
public System.DateTime submission_date { get; set; }
public virtual ICollection<abstract_author> abstract_author { get; set; }
public virtual ICollection<abstract_category> abstract_category { get; set; }
public virtual ICollection<abstract_questions> abstract_questions { get; set; }
}
var meeting_abstract = new meeting_abstract();
meeting_abstract.meeting_id = meetingAbstract.Meeting.meeting_id;
meeting_abstract.submission_date = DateTime.Now;
meeting_abstract.abstract_questions = new Collection<abstract_questions>();
var abstractQuestion = new abstract_questions();
abstractQuestion.meeting_question_id = Convert.ToInt32(meetingAbstract.AbstractTitleInEnglishId);
abstractQuestion.abstract_question_answer = meetingAbstract.AbstractTitleInEnglishText;
meeting_abstract.abstract_questions.Add(abstractQuestion);
abstractQuestion = new abstract_questions();
abstractQuestion.meeting_question_id = Convert.ToInt32(meetingAbstract.AbstractTitleInLanguageId);
abstractQuestion.abstract_question_answer = meetingAbstract.AbstractTitleInLanguageText;
meeting_abstract.abstract_questions.Add(abstractQuestion);
meeting_abstract.abstract_author.Add(meetingAbstract.primaryAuthor);
var abstractCategory = new abstract_category()
{
meeting_category_id = meetingCategory.meeting_category_id
};
meeting_abstract.abstract_category = new Collection<abstract_category>();
meeting_abstract.abstract_category.Add(abstractCategory);
_abstractRewriteEntities.meeting_abstract.Add(meeting_abstract);
_abstractRewriteEntities.SaveChanges();
Whats wrong here? I cannot save all together?
When adding more than one item, with a property defined as the identity, you will need to give those entities a unique key even though it will ultimately be set by the db. We do this in our project by defining a partial class for that entity, and in OnCreated making sure they have a unique value for their identity.
For example:
public partial class abstract_questions
{
private static int _newIdentity = 0;
partial void OnCreated()
{
//Set an identity value so when two new entities
// are created Entity Framework doesn't whinge
// on the server because of duplicate keys
_newIdentity = _newIdentity - 1;
// Set whatever is defined as the identity/pk property
this.Id = _newIdentity;
}

EF4.1 Model with complex type with Primary Key as string not working well

I have the following two models
[DataContract]
public class Event
{
[Key]
public int ID { get; set; }
public string Name { get; set; }
public Place Place { get; set; }
}
[DataContract]
public class Place
{
[Key]
public string ID { get; set; }
public string Name { get; set; }
}
and data context class:
public class myDB: DbContext
{
public DbSet<Event> Events { get; set; }
public DbSet<Place> Places { get; set; }
}
I run the following code for example
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
Foo();
}
private void Foo()
{
var db = new myDB();
var place = new Place
{
ID = "{59E0F90C-03DB-453C-8C9E-4747957ED37E}",
Name = "Home",
};
db.Places.Add(place);
db.SaveChanges();
var #event = new Event
{
Name = "Test",
Place = place,
TimeFrame = new TimeFrame() {StartTime = DateTime.Now, EndTime = DateTime.Now }
};
db.Events.Add(#event);
db.SaveChanges();
var eventIndex = #event.ID;
var ev = db.Events.Find(#eventIndex);
var evPlace = ev.Place;
var pl = db.Places.Find("{59E0F90C-03DB-453C-8C9E-4747957ED37E}");
}
everything works fine and evPlace is the object I just added to db, pl is also not null.
But when I try to run the following code from the controller where 5 is the ID of the new event object
var ev = _db.Events.Find(5);
var evPlace = ev.Place;
var pl = _db.Places.Find("{59E0F90C-03DB-453C-8C9E-4747957ED37E}");
pl and ev are not null but ev.Place is null (evPlace)
Any idea why?
The problem has nothing to do with the primary key being a string or not. Generally Entity Framework doesn't load navigation properties automatically. You need to specify that explicitly:
var ev = db.Events.Include(e => e.Place).SingleOrDefault(e => e.ID == 5);
Or: If you declare the Place property as virtual...
public virtual Place Place { get; set; }
...EF will enable lazy loading for this property and load the Place from the database as soon as you access it in your code. Your code example would work then. Be aware that lazy loading leads to a second query/roundtrip to the database whereas eager loading (Include) loads both the event and the place in a single query.
More about loading related entities is here.

Categories