EF Core SQLite - Can't insert NULL into timestamp - entity-framework

Using in memory EF Core SQLite for integration tests. When creating an entity with the following column definition:
entity.Property(e => e.TxTimestamp)
.IsRequired()
.IsRowVersion()
.IsConcurrencyToken();
Setting with
TxTimestamp = new byte[8] { 0, 1, 2, 3, 4, 5, 6, 7 }
I get the following error:
Microsoft.Data.Sqlite.SqliteException : SQLite Error 19: 'NOT NULL constraint failed: [TableName].TxTimestamp'.
Any ideas? It is like SQLite isn't inserting the value. Perhaps because with real SQL Server it wouldn't be able to? This model is generated from the Db so I can't just change the model builder definition.

Related

How to fix EF Core migration error on join table configuration

Using EF core 6.0.1, I'm following the example shown here for configuring the join table for a many-to-many relationship in a migration, but I can't get past this error:
The seed entity for entity type 'Classifier' cannot be added because
no value was provided for the required property 'Id'.
modelBuilder.Entity<Classifier>().HasData(
new Classifier
{
Id = 1,
Name = "Concerto",
}
);
modelBuilder.Entity<Composition>()
.HasData(
new Composition
{
Id = -1,
Name = "First Composition",
CreatorId = -1,
LastModifierId = -1,
CreatedDate = DateTime.Parse("01/01/2019"),
LastModifiedDate = DateTime.Parse("01/01/2019"),
Summary = "Lorem ipsum",
}
);
modelBuilder.Entity<Classifier>()
.HasMany(cl => cl.Compositions)
.WithMany(cm => cm.Classifiers)
.UsingEntity(j => j.ToTable("ClassifierCompositions")
)
.HasData(
new { ClassifiersId = 1, CompositionsId = -1, },
);
I've verified that the names used in the anonymous type used to configure the join match the autogenerated column names from EF. I suspect the error message is a poor representation of the real error, since clearly the Classifier.Id is provided. Why is this error being thrown?
Fwiw, the Composition table exists already as created by a previous migration and this migration is adding the Classifier table and join table.
I suspect the error message is a poor representation of the real error, since clearly the Classifier.Id is provided. Why is this error being thrown?
Actually the error is correct. It's because here
modelBuilder.Entity<Classifier>()
.HasMany(cl => cl.Compositions)
.WithMany(cm => cm.Classifiers)
.UsingEntity(j => j.ToTable("ClassifierCompositions")
) // <-- the problem
.HasData(
new { ClassifiersId = 1, CompositionsId = -1, },
);
you are executing the UsingEntity call, which returns EntityTypeBuilder<Classifier>, so the next HasData call is actually defining more Classifier data entries via anonymous type which of course has no Id property, hence the error message.
The correct action of course is to define the seed data for the join entity, using its entity builder inside the UsingEntity call, i.e.
modelBuilder.Entity<Classifier>()
.HasMany(cl => cl.Compositions)
.WithMany(cm => cm.Classifiers)
.UsingEntity(j => j
.ToTable("ClassifierCompositions")
.HasData(
new { ClassifiersId = 1, CompositionsId = -1, },
)
);

Entity Framework Core: Cannot update identity column 'Id'

I found related question but my issue seems to be different.
Running the following code:
var dbitem = context.MyDatabaseItems.Single(p => p.Id == someId);
context.Update(dbitem);
context.SaveChanges();
Results in "Cannot update identity column 'Id'". Table behind is a bit special. "Id" is NOT the primary key for different reasons. Primary key consists of combination of other fields. No matter what I do: detaching, reattaching etc etc the existing item I am unable to save the entity even if I do not change it (see the code).
However this Id is unique and auto generated.
The builder is the following:
builder.Property(p => p.Id)
.ValueGeneratedOnAdd();
builder.HasKey(p => new { p.BusinessDay, p.ClientId, p.Version });
BusinessDay is dateTime, CLientId and Version are integers.
What is going on here?
There are two metadata properties which control the update behavior called BeforeSaveBehavior and AfterSaveBehavior.
For auto generated keys the later is assumed to be Ignore, i.e. never update. For non key auto generated properties it must be configured explicitly (note that there is no fluent API for that so far, so you have to use the metadata API directly), e.g.
// First define the new key
builder.HasKey(p => new { p.BusinessDay, p.ClientId, p.Version });
// Then configure the auto generated column
// This (especially the `SetAfterUpdateBehavior` call) must be after
// unassociating the property as a PK, otherwise you'll get an exception
builder.Property(p => p.Id)
.ValueGeneratedOnAdd()
.Metadata.SetAfterSaveBehavior(PropertySaveBehavior.Ignore); // <--
This does not change the database schema (model), hence no migration is needed. Just the EF Core update entity behavior.

EF Core + Sqlite 3.24.0 throws exception in trigger with UPSERT operation

I'm using EF Core 2.1 and my testing db is Sqlite 3.24.0.
In my database. There is one trigger which is:
CREATE TRIGGER IF NOT EXISTS OnTopicInsert
AFTER INSERT ON Topic
WHEN Topic.Status == 1
BEGIN
INSERT INTO CategorySummary(CategoryId, TotalPost, TotalFollower, LastTopicId, LastTopicTitle, LastTopicCreatedTime)
VALUES(Topic.CategoryId, 1, 0, Topic.Id, Topic.Title, Topic.CreatedTime)
ON CONFLICT(CategoryId)
DO UPDATE
SET TotalPost = TotalPost + 1,
LastTopicId = Topic.Id,
LastTopicTitle = Topic.Title,
LastTopicCreatedTime = Topic.CreatedTime;
END
What I want in the trigger is:
When a Topic is created, CategorySummary will be inserted if does not exist and update if it does.
Without the trigger, my app was OK. After inserting that trigger into my sqlite 3.24.0. There is one exception thrown back:
SQLite Error 11: 'malformed database schema (OnTopicInsert) - near "ON": syntax error'.
Can anyone help me ?
Thanks,

Eloquent default attribute values: $attributes or DB column default value?

What's the proper way to implement default values for Eloquent models?
I've configured my database tables using Laravel's migrations. Some columns have default values specified. When using these tables in conjunction with Eloquent models, different things happen depending on the selected database driver:
In MySQL, when creating a new model and saving it, a DB row is inserted having the column's default value for every attribute that was not explicitly specified. This is what I would like to happen.
In Postgres and SQLite however, this is not the case. A PDOException is thrown:
[PDOException]
SQLSTATE[23502]: Not null violation: 7 ERROR: null value in column
"some_column" violates not-null constraint
DETAIL: Failing row contains (1, 2, 3, 4, 5, 6, null, null, null, null, null, null, 7, 8, null, 9, null, null, 10, 11, 12, null).
It is clear to me that the column is not nullable and that null values are not accepted. I would expect however that the default value was inserted instead of an error being raised.
I would suggest that you create your own parent model that extends Eloquent directly, and have all of your models extend this custom parent.
In the custom parent, override the performInsert() method to remove null values just before inserting. Be sure to copy the entire method from the Eloquent source code so you don't lose any important steps in the process:
class MyModelParent extends Illuminate\Database\Eloquent\Model
{
/**
* Perform a model insert operation.
*
* #param \Illuminate\Database\Eloquent\Builder $query
* #return bool
*/
protected function performInsert(Builder $query)
{
if ($this->fireModelEvent('creating') === false) {
return false;
}
... // Be sure to copy all of it!
// This is the change you'll make. Before, it was just:
// $attributes = $this->attributes;
$attributes = array_filter($this->attributes, function($val){
return $val !== null;
});
... // Be sure to copy all of it!
return true;
}
}
performUpdate() should handle this issue fine, since it uses getDirty() to get the list of fields instead of accessing the property directly.
And while you're at it, you should consider submitting a patch to Laravel that would make the core Postgres-safe.
SQL NOT NULL Constraint
The NOT NULL constraint enforces a column to NOT accept NULL values.
you are adding a null value on NOT NULL column
it seems
http://www.w3schools.com/sql/sql_notnull.asp

Sybase ASE Entity Framework - Error while updateing record to database -"incorrect syntax near '('.\n"

I am trying to simple update and existing record. And I am getting the error - incorrect syntax near '('.\n
Entities db = new Entities();
try
{
var existingObj = new OBJETE
{
OB_ID_MR = 348,
OB_ID_JE = 1156,
OB_IS_NT = false,
OB_ID_MS = 88,
OB_POSITIONABS = "12,12,12,12",
OB_ORDRE = 1,
OB_UPDATEDATE = DateTime.Now
};
db.OBJETEs.Attach(existingObj);
db.ObjectStateManager.ChangeObjectState(existingObj, System.Data.EntityState.Modified);
db.SaveChanges();
If I try to update "not null" columns then I can update the records in this table. But when I try to update nullable values then I am getting this error consistently. Please advice.
Found it! My Table did not have a Primary Key. Entity Framework add some addition tag to disable update of such tables.
So either you add a primary key to the table or if that is not an option like in my case the work around is to open the edmx file in Text mode, and remove the entry for the tag - "DefiningQuery" and all its contents for the Table in question. Additionally we need to change => store:Schema="dbo" to Schema="dbo" for that Table. This should fix the issue.