The two attributes [IgnoreOnInsert] and [IgnoreOnCreate] do not work when using db.Save, they do work when using db.Insert and db.Update, but that means I have to do a retrieval and check before inserting. Could this be fixed or have a IgnoreOnSave added ?
This is also what Save()
does behind the scenes.
Can you please provide a stand-alone example showing what doesn’t work? Save calls the same Insert and Update APIs behind the scenes.
I have a model which includes a field SiteID which I want to ignore when persisting.
[Ignore]
public Guid SiteID { get; set; }
I wanted to populate this field using a custom query e.g.
var query = "SELECT DISTINCT d.SiteID, ds.* FROM DeviceStatus ds " +
"Left Join Device d on ds.DeviceID = d.ID " +
"Where (ds.Active = 1) ";
var deviceStatuses = db.Select<DeviceStatus>(query);
This did not work with the Ignore attribute and always came out as an EmptyGuid. So I attempted to decorate the field with the following attributes
[IgnoreOnInsert, IgnoreOnUpdate]
public Guid SiteID { get; set; }
This correctly populated the field from the query, but when I used the following:
db.Save<DeviceStatus>(request.DeviceStatus);
It complained of a missing field in the database. Changing my code to the following:
var old = Any(new GetDeviceStatus() { AccountID = request.AccountID, ID = request.DeviceStatus.DeviceID });
if (old != null){
db.Update<DeviceStatus>(request.DeviceStatus);
} else
{
db.Insert<DeviceStatus>(request.DeviceStatus);
}
This works but isn’t very elegant.
I don’t have your source code or db state to be able to repro this locally, I’d need an stand-alone example I can run locally, e.g. like an example on Gistlyn.
ok I will provide it, just may take me a few days.
I have created a bare bones solution which demonstrates the error.
It is available here:
Instructions can be seen in the interface class.
It does require MySQL unfortunately. I was unable to reproduce using Gistlyn which made me wonder if it is a .Net Core bug only.
This wont work because to work out if a record exists in Save behind the scenes has to call SelectBId<T>
which is going to attempt to select these fields since they’re apart of the table definition.
So you need to tell OrmLite not select these fields in its SELECT queries, which you could do with a CustomSelect Attribute where you can tell OrmLite what to select instead, e.g:
public class Status
{
[PrimaryKey]
public Guid DeviceID { get; set; }
[CustomSelect("NULL")]
public Guid SiteID { get; set; }
[CustomSelect("NULL")]
public Guid GroupID { get; set; }
}
But really you basically have 2 different incompatible models that you’re trying to combine into 1. Since you’re using a custom Query you should be using a different model to populate the table that matches the schema of custom query you’re returning and the Status
table should match the table schema you’re trying to insert into, e.g:
public class Status
{
[PrimaryKey]
public Guid DeviceID { get; set; }
}
//[Alias(nameof(Status)] Optional. Not required if you're using a custom query
public class StatusView
{
public Guid DeviceID { get; set; }
public Guid SiteID { get; set; }
public Guid GroupID { get; set; }
}
Note: If your Primary Key field is not called Id
you should annotate it with a [PrimaryKey]
attribute, this isn’t required for your custom select models which you aren’t Inserting or Updating.
Thanks Mythz, yes that makes perfect sense. If I am loading the StatusView in this case, I would need to Save a status, what is the most efficient way to copy all Status properties from StatusView ?
The most efficient way is to use C# to manually copy the properties, the most convenient way is to use Auto Mapping i.e:
var status = statusView.ConvertTo<Status>();
The Auto Mapping uses cached compiled delegates so it’s still fast, but will never be as fast as direct MSIL from using C#.
Thanks, appreciate it