EF Core: conditionally computed column - asp.net-core

In my model I have AccountType property, which is mostly generated by database trigger, but sometimes can also be directly assigned:
public class Account
{
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public int AccountType { get; set; }
}
The attribute [DatabaseGenerated] allows me to automatically get database generated value back, whenever databaseContext.SaveChanges() executed.
However, this attribute seems to also prevent sending a value, if
I wish to assign AccountType explicitly. What is the best way to implement such "partially" generated/computed column?

However, this attribute seems to also prevent sending a value, if I wish to assign AccountType explicitly. What is the best way to implement such "partially" generated/computed column?
If you want to set a explicit value to a property decorected with [DatabaseGenerated(DatabaseGeneratedOption.Computed)] , you need to drop down to the lower level metadata API and set AfterSaveBehavior/BeforeSaveBehavior like below :
IMutableProperty.BeforeSaveBehavior Property is used for Add state
modelBuilder.Entity<Test>()
.Property(t => t.TestType)
.Metadata.BeforeSaveBehavior=PropertySaveBehavior.Save;
IMutableProperty.AfterSaveBehavior Property is used for Update state
modelBuilder.Entity<Test>()
.Property(t => t.TestType)
.Metadata.AfterSaveBehavior =PropertySaveBehavior.Save;
The PropertySaveBehavior indicates how changes to the value of a property will be handled by Entity Framework change tracking which in turn will determine whether the value set is sent to the database or not.

Related

Required attribute in Data Annotations

I'm using MVC 4 and Entity Framework 5 to build my website. To validate data in client side, I use Data Annotations. Here is my property in View Model:
public int Salary { get; set; }
As you can see, I don't put any annotation there. Also, in my database, the Salary column was marked as Allow null.
My problem is whenever I submit my form, the ModelState is invalid because of this property. It thinks that this property is required and display error on client side.
Do you know what causes the problem? Please help me. Thanks a lot.
The issue you are having is because the default constructor initializes the property to 0. If you want to allow nulls do this:public int? Salary { get; set; }

Changing the value of an Id in RavenDB

We have an entity named Organization that we use the UniqueConstraints-bundle on. We have a property named NetName that is a UniqueConstraint and an automaticly generated Id.
Since this is unneccesary we want to use the NetName-property as Id instead. So that we don't need UniqueConstraints to know that it is unique and also get the benefit from being able to use Load when we have the NetName.
We needed to clean up our netname a bit before using it as an Id so we created a new temporary-property called TempUniqueNetName that now holds the value of:
"organizations/"+ CleanupId(this.NetName)
So we are now ready to simply move that value to our Id. But we can't get it to work. Our problem is that with the PatchRequest below we end up with a new property named Id in the database but the acctual Id still has the same value (see screenshot). Is there a better (correct) way to change the value of an Id?
The Entity:
class Organization {
public string Id { get; set; }
[UniqueConstraint]
public string NetName { get; set; }
public string TempUniqueNetName{ get; set; }
}
We want to do something like this:
_documentStore.DatabaseCommands.UpdateByIndex(typeof(Organizations).Name,
new IndexQuery(),
new[]
{
new PatchRequest()
{
Type = PatchCommandType.Rename,
Name = "TempUniqueNetName",
Value = new RavenJValue("Id")
}
});
I don't think you can change the document key via patching. It's not actually stored with the document or the metadata - it's copied into the #id metadata on load to give you the illusion that it's there, and the Raven Client copies it again into your own identity property in the document. But really, it's a separate value in the underlying esent document store. Raven would have to know specifically how to handle this and fake it for you.
You could manually copy the doc from the old id to the new one and delete the old, but that could be time consuming.
There isn't a great answer for renaming a document key right now. There really should be a DatabaseCommand for rekeying a single document, and separate PatchCommandType to rekey when patching. Perhaps this will be added to raven in the future.
You can check implemtation of PUT-DELETE usage for updating IDs in my github repo.
It should look something like this:
store.DatabaseCommands.Put(updatedKey, null, document.DataAsJson, newMetadata);
store.DatabaseCommands.Delete(oldKey, null);
https://github.com/Sevsoad/SagaUpdater/
Also here is some Raven documentation:
https://ravendb.net/docs/article-page/3.0/csharp/client-api/commands/documents/put

IFindSagas with Raven saga persistence and multiple properties in NServiceBus

I am using Raven to persist sagas and I want to implement IFindSagas, I need to find the saga based on 2 properties, SiteId & EmailAddress so ConfigureMapping won't work. The ISagaPersister interface only lets you look up a single saga by a single property.
I have implemented a saga finder like this
public class MySagaFinder : IFindSagas<MySagaData>.Using<ISomeMessage>
{
public ISagaPersister Persister { get; set; }
public MySagaData FindBy(ISomeMessage message)
{
var lookup = string.Format("{0}__{1}", message.SiteId, message.EmailAddress);
return Persister.Get<MySagaData>("SagaLookup", lookup);
}
}
So basically I've added a property on MySagaData called SagaLookup which is a concatenation of SiteId and EmailAddress. I can then look it up by this. This feels like a hack. Is there any way using the saga persister that I can either get a saga back by multiple properties or get a list of sagas back based on one property that I can then filter by the other property?
IMO it is best to look up by a single "key" property because then you don't need to implement a custom persister. Concatenating the site ID and email address may seem like a hack, but if you think of that as defining the ID of that specific saga then it makes sense. The saga data isn't part of your domain model, it is part of the infrastructure which has specific requirements. However, you should consider whether this definition of the saga ID is unique enough. For example, would it ever be possible for two saga's for the same user in the same site ID to execute at the same time?

How to write null to Guid? field in DB?

I have a guid? field in my POCO and when I create a new entry in my DB and look at it through SSMSE, I see NULL in that field. After choosing a manager for this new user entry, the guid? field is updated to hold the id of the new manager. However, if I want to change the user back to having no manager, how can I set the field back to NULL?
Should I be using Guid instead of Guid? and write Guid.Empty to the DB instead?
Should I be using Guid instead of Guid? and write Guid.Empty to the DB instead?
Not really. You could do that, but you wouldn't really gain much. Semantically, if there is "no" value for a field, NULL is the correct value. What you are talking about is using a magic value.
how can I set the field back to NULL?
Set the Guid? to null on your POCO. For example, if your POCO looks something like this:
public class Poco
{
public Guid? Manager { get; set; }
}
Set it to null like this:
somepocoinstance.Manager = null;
Then commit the changes.

How do I serialize/deserialize a NHibernate entity that has references to other objects?

I have two NHibernate-managed entities that have a bi-directional one-to-many relationship:
public class Storage
{
public virtual string Name { get; set; }
public virtual IList<Box> Boxes { get; set; }
}
public class Box
{
public virtual string Box { get; set; }
[DoNotSerialize] public virtual Storage ParentStorage { get; set; }
}
A Storage can contain many Boxes, and a Box always belongs in a Storage. I want to edit a Box's name, so I send it to the client using JSON. Note that I don't serialize ParentStorage because I'm not changing which storage it's in.
The client edits the name and sends the Box back as JSON. The server deserializes it back into a Box entity.
Problem is, the ParentStorage property is null. When I try to save the Box to the database, it updates the name, but also removes the relationship to the Storage.
How do I properly serialize and deserialize an entity like a Box, while keeping the JSON data size to a minimum?
I would recommend you send a DTO to the client for display purposes (and it should contain the unique database ID). Then send the boxId + the new name back up to the server from the client (there is no need to send the entire DTO back). The server can do a database lookup using the ID to get the box object, update the name field to the one sent from the client, and save the box to the database.
There is no need in this scenario to serialize an NHibernate object, that just adds a lot of complexity and no value.
I would guess that ParentStorage is null because it is being lazily loaded. Either configuring it to be fetched eagerly or forcing a read by calling the getter before serialization may help make sure the Storage is serialized, and depending on your ID scheme this may work (I don't know for sure).
The gains from serialization in this case seem minimal, and may have unexpected consequences as the Box and Storage classes evolve. It seems simpler to send up a single string for the name, load the Box, set the string, and save that object. Then you don't have to worry as much about the optimizations Hibernate does underneath.