All of my datamodels have field DateAdded. When the user (through MVC Web API) sends a request to save a model, the serverside populates this field with a DateTime object, and then proceeds to save the object via hibernate.
Now consider the case of updating. Even if the user modifies the DateAdded field manually, it should not change the value in the database. Is there a way that I can specify for this field to NOT be updated, regardless of what the user provides? If the field is not populated by the user, the datetime field becomes null, which is also no good.
Turns out there's a property for this you can set in the hbm file!
Simply set update="false" on all properties that you don't want to be updateable. Sorry for not doing more research before wasting precious SO resources.
Change all your mappings to:
<property name="DateAdded" update="false">
<column name="DateAdded" sql-type="smalldatetime" not-null="true" />
</property>
Related
I have a class with a field:
protected DateTime insertDate;
This is mapping for this fiels:
<property name="InsertDate" access="field.camelcase" update="false" />
This field is set when with ctor
public DocuBase(DateTime insertDate)
and is persisted only when row is added to the database. I don't need property for it at all, no setter & no getter. I worked in NHibernate 3.
And now, I've moved from NHiberbate 3 to NHibernate 3.3.1, and I get this exception when session factory is created:
Could not find the property 'InsertDate', associated to the field
'insertDate', in class 'XXXX'
Why is is happening & how can I change mapping in order to get rid of the exception?
EDIT: Below answer is completly correct. But for those of you that don't need/don't want to have a property, and only field, there's another solution:
set name attribute to field name (in my case it is insertDate) and remember to have correct column name
<property name="insertDate" column="InsertDate" access="field.camelcase" update="false" />
It is case sensitivity, this will work.
<property name="insertDate" column="InsertDate" update="false" />
Looks like in release 3.1.0, there was a breaking change
NH today accepts code below. It would be better if this would throw - it causes problem when configurate NH (or 3rd party tools) other ways than by hbm, using the property name (or memberinfo) of the public interface.
[hbm]
<property name="Name" access="field.camelcase" />
[code]
string name;
public virtual string SomeThingCompletelyDifferent{
get {return name;}
set{name=value;}
}
Note: This will be a breaking change.
ps - updated answer to remove reference to use Property with private set as this was not what was being looked for and above breaking change is more relevant.
I'm very new to NHibernate so this may be fairly trivial, but searching is leaving me confused.
I have an AddOnAmount table as follows:
AddOnID | AddOnTypeID | Period | Amount
where AddOnTypeID is a FK. The rows have a unique constraint on AddOnTypeID and Period.
The mapping looks like this:
<id name="Id" column="AddOnId" type="long">
<generator class="native" />
</id>
<many-to-one name="AddOnType" column="AddOnTypeID" class="AddOnTypeStatic" not-null="true" />
<property name="Period" />
etc.
The AddOnTypeStatic class/table just has an Id, which is the numerical value stored on the table, and a descriptive Name.
I'm trying to write a query that will search by AddOnTypeId and Period, so I can validate the existence (or not) of a row before attempting to add a duplicate from my front end, but I'm not sure how to do that as the AddOnAmountStatic class has a subclass whereas the table has just an Id.
So far I've written:
public AddOnAmountStatic FindByAddOnTypeAndPeriod(long addOnType, string period)
{
return FindOne(CreateCriteria()
.Add(Restrictions.Eq("AddOnTypeId", addOnType))
.Add(Restrictions.Eq("Period", period))
.SetCacheable(true));
}
which does not work, as AddOnTypeId isn't a property of AddOnAmountStatic. Not sure how to access the property of the subclass in this context.
My mapping works, as I've been using it so far with no problems.
Solved my problem - it was simple but thought I'd add the solution here in case it helps anyone else.
I'd been thinking of constructing the query from the table's perspective (i.e., with the AddOnTypeID), whereas what I should have done is look at it from the entity's perspective. In other words, I just needed to pass in an AddOnTypeStatic object.
What I did was take my AddOnTypeID parameter, check it exists through NHibernate (returning either an AddOnTypeStatic object or null) then passed that through to the original query. Final query is simply
return FindOne(CreateCriteria()
.Add(Restrictions.Eq("AddOnType", addOnType))
.(Restrictions.Eq("Period", period))
.SetCacheable(true));
Hope this helps another newbie!
Visual studio is giving me a trail of errors that I have hit a dead end on. I am trying to add an existing table in a database to my data model. I understand that the table should have a key, but it doesn't and I can't fix that; it isn't my database to re-design.
When I first try to add the table, I get this error:
The table/view
'BT8_GC.dbo.SAVED_QUERY_CATEGORY' does
not have a primary key defined and no
valid primary key could be inferred.
This table/view has been excluded. To
use the entity, you will need to
review your schema, add the correct
keys, and uncomment it.
Ok, fine, I'll define the keys for it and uncomment. Here is the block I uncomment, after manually defining the keys (I also had to add the nullable=false part):
<EntityType Name="SAVED_QUERY_CATEGORY">
<Key>
<PropertyRef Name="SQC_CAT_ID"/>
<PropertyRef Name="SQC_USER_ID"/>
</Key>
<Property Name="SQC_CAT_ID" Type="int" Nullable="false" />
<Property Name="SQC_USER_ID" Type="int" Nullable="false" />
<Property Name="SQC_CAT_DSCR" Type="varchar" MaxLength="50" />
<Property Name="SQC_SEQ_NO" Type="int" />
</EntityType>
Nope, now the designer won't open. Go back into the file, and Intellisense shows this error:
Error 11002: Entity Type 'SAVED_QUERY_CATEGORY' has no entity set.
Ok... Uncommenting created a new error. After adding an entity set:
<EntitySet Name="SAVED_QUERY_CATEGORY" EntityType="IssueModel.Store.SAVED_QUERY_CATEGORY" store:Type="Tables" Schema="dbo" />
Yay! The designer opens! Still not there yet, because while it shows up under the store's Tables/Views folder, it has not Entity Type in the model. Can't call it from my code. I don't have any errors to work off though, so I tried creating an entity set mapping, but that results in the error "does not exist in MetadataWorkspace".
So that's what I have tried. How do I get this poorly designed table into my data model?
By modifying XML you have only added information about database table. Now you have to open toolbox and add entity to your model in the designer. Configure the entity to have properties as you need. Then open mapping details and map the new entity to your table.
Btw. once you modify the XML describing database manually you cannot use update from database anymore - VS designer will always delete your changes and you will have to do them again.
VB .NET 4 WinForms application.
I have a (DevExpress) grid bound to an IEnumerable(Of MyClass).
Whenever a new row is added, the ID defaults to zero (0). On trying to SaveChanges, EntityFramework doesn't realise that being an identity field means it should ignore any contents on insert and just insert the other values. I can't specify null / Nothing because it just keeps the ID as zero.
I can add and save instances of MyClass manually, but I'm trying to get it to work where the grid handles adding/initialising/etc new entries. As far as I can tell, the problem is not with the grid but with Entity Framework and the generated SQL and entity classes.
{"Cannot insert explicit value for identity column in table 'MyClasses' when IDENTITY_INSERT is set to OFF."}
Any assistance to prevent me from throwing my laptop out a window would be greatly appreciated!
If a property of an Entity is an Identity (auto-incrementing value) in the database is specified in the StorageModel of your Entity Model. Perhaps this setting is not correct for your particular field. You can check this by opening the edmx file of your model and looking into the StorageModels section. It should look like this:
<edmx:StorageModels>
...
<EntityType Name="MyClass">
<Key>
<PropertyRef Name="ID" />
</Key>
<Property Name="ID" Type="..." Nullable="..." StoreGeneratedPattern="Identity" />
...
</EntityType>
...
</edmx:StorageModels>
StoreGeneratedPattern must be set to Identity. If there is None or the attribute is missing (which defaults to None) you get indeed the error you described since EntityFramework doesn't know in this case that ID is an identity and will issue a value for the column in the generated SQL-INSERT statement.
(Make sure you are really checking the edmx:StorageModels section in the edmx file. The edmx:ConceptualModels section has an attribute annotation:StoreGeneratedPattern in the property as well but its setting doesn't matter for your specific problem. (I think that's only important when a database gets created from a model, but I'm not sure.))
I have a web page which uses NHibernate to load a domain object. The object's state is then stored in the page controls, and when the user clicks the save button, a new object is created and its properties (included the Id) are populated from the page controls. I then call session.Save() on the object.
This to me means that NHibernate should use an UPDATE rather than an INSERT, because the Id property has been set and differs from the unssaved-value. However, NHibernate is attempting to insert it.
I have included the part of the mapping file relating to the Id below:
<id name="Id" column="StoredWillId" unsaved-value="0">
<generator class="native" />
</id>
Can anyone explain what's going on here?
Thanks
David
Call session.SaveOrUpdate(). session.Save() inserts, session.Update() updates, session.SaveOrUpdate() saves if Id is 0, otherwise updates.