Just recently tried OrmLite for MySql in a C# console project:
I'm loving it, since it's easy to implement with MySql, in contrast to Entity Framework. However I'm trying to enable automatic updates of the database schema from my model. I extended the code given in the answers in:
With OrmLite, is there a way to automatically update table schema when my POCO is modified?
And came up with a solution that can add and delete columns in your database schema, depending on the model. Works pretty good, and utilizes a lot of the features OrmLite.ModelDefinition gives.
See the solution here:
https://github.com/contradel/Extending-NServiceKit.OrmLite
However I can't get it to automatically create foreign keys with GetDialectProvider.ToAddForeignKeyStatement(). And I can't find any documentation. Does anyone know how it works?
I would like to be able to do this:
public class Order
{
//Try to add or comment out properties here, SQL will be generated automatic
[AutoIncrement]
public int Id { get; set; } //pk
public DateTime? OrderDate { get; set; }
[References(typeof(Customer))] //Creates Foreign Key
public int CustomerId { get; set; }
}
And then:
foreach (FieldDefinition field in missingOnDb)
{
//if (field != ForeignKey)
var addSql = string.Format(db.GetDialectProvider().ToAddColumnStatement(typeof(T), field));
//else
//addSql = db.GetDialectProvider().ToAddForeignKeyStatement(??,??,??,??,??);
Console.WriteLine(addSql);
db.ExecuteSql(addSql);
}
Related
Using Entity Framework, how can I insert data if it does not exist, and update a field if it does?
public class Rootobject
{
public string odatacontext { get; set; }
public Value[] value { get; set; }
}
public class Value
{
public int AccountId { get; set; }
public DateTime? SubmissionDate { get; set; }
public string Status { get; set; }
}
To retrieve all the data from my API I use
root.value.Select(x => new satiaL
{
accountID = x.AccountID,
subDate = x.SubmissionDate,
x_status = x.Status
});
which of course will insert all records.
If the AccountID already exists in the database, I want to update the value of x_status, but if the AccountID does NOT yet exist in the database, then I want to insert all values.
You can not.
Upsert functionality is not part of an object/relational model - objects are there or not, and tracked by identity. Thre is no "update if it is not there" concept - at all. So, there is nothing for EfCore to implement.
This smells like abusing an ORM as a ETL loader, and this is not what you should do - ETL (mass data loading) is not what and ORM is made for. Time to write your own method to move data up into tables and possibly do upswert there. Did that years ago, comes really handy at times.
Right now all you can do is run a lot of finds for every account and basicalyl write code: create if not exists, update if exists.
Pseudocode:
var account = Find ( select ) or default from db
if account == null create
else update
savechanges
Something along this line. Beware of performance - you may want to just builk load all accounts. Beware of conflicting updates.
I have a quick question and looking for the best way to do this, whether EF has the capability or not, am not sure? I am using EntityFramework 6.3.
I have the following parent-child scenario,
public class Application{
[Key]
public int ApplicationId {get;set;}
public string Name {get;set;}
public string Status {get;set;}
public virtual List<Document> Documents {get;set;}
}
public class Document{
[Key]
public int DocumentId {get;set;}
[Index("IX_ApplicationDocument", 1, IsUnique = true)]
public string DocumentType {get;set;}
[Index("IX_ApplicationDocument", 1, IsUnique = true)]
public string Name {get;set;}
public int ApplicationId {get;set;}
[ForeignKey("ApplicationId")]
public Application Application {get;set;}
}
So an application is made to a department, and stored in the database, each application has a status and when submitted, status of pending, because various validation has to occur before it is approved. When an application is rejected, the submitter has to make a new application (please note I used a minimalistic example than what it actually is), however, the applicant may submit the same documents again. The problem is, this already exist in the system and can not be duplicated. As you can see, the second time they attempt to submit it will throw a constraint exception. How can I overcome this using EF, is there a way to create a constraint based on the parent's status, or is this something that can only be done programmatically?
Dont know if its helps you in your case or not, but check this out
Assuming your entity is defined as
public class Entity
{
public int Id { get; set; }
public int Parent { get; set; }
public int Child { get; set; }
}
Following fluent API code will create index as you desire:
modelBuilder.Entity<Entity>().HasIndex(p => new {p.Parent, p.Child})
.HasFilter("isdeleted = 0")
.HasName("unq_t_parent_child");
SQL generated
CREATE INDEX [unq_t_parent_child] ON [Entity] ([Parent], [Child]) WHERE isdeleted = 0;
HasIndex defines index over properties in the table Entity
HasFilter allows you to set a filter for your index. This value is sql so you need to make sure you are writing correct sql syntax.
HasName configures the name of the index.
(If you map Entity to table t & the properties to their column names, migrations will create exactly same sql as you want.)
Also a check constraint is different from unique index. If you are looking to add check constraint then you need to use migrationBuilder.Sql in your migration file.
So unfortunately I have searched around and there is no solution for this for EF 6. The best way I can do this was following the guidance of the following article, where you manually add the Filtered Index in your migration after table creation.
Blog
Is it possible to read and write to a SQL Server database using DataTable with Entity Framework?
I have multiple code tables defined in my database such that each of them share a fixed set of properties as shown in the sample below.
For example
public class CTGender
{
public Guid ID { get; set; }
public string Description { get; set; }
public string DisplayValue { get; set; }
//...Other properties specific to CTGender
}
public class CTNationality
{
public Guid ID { get; set; }
public string Description { get; set; }
public string DisplayValue { get; set; }
//...Other properties specific to CTNationality
}
The situation I face right now is the ever expansion of my code tables, could be another CTCountry, CTRole and so on, for example.
I am trying to synchronise these code tables between multiple databases.
The solution is heavily dependent on Entity Framework as the data access.
Is there a generic way for Entity Framework to read and write ALL these code tables without their entity models defined, like how you can read and write generic DataTables using ADO.NET?
Yes, there are couple of ways by which you can create tables at code side then either using code first approach or using publish project mechanism you can generate tables in SQL server using entity framework.
In the latter approach, you can create a separate project where you can write SQL for your various tables. This project should target SQL Server. You can right click on this project and click on publish option for updating all your tables inside SQL server.
Problem
I have a situation whereby I need to use Entity Framework 6, Code First, with a legacy database structure which cannot be changed. The database has a very generic table which stores text based data alongside some non key data which can be used to relate the record back to another table.
To illustrate:
Assume the Notes table has a model as follows:
[Table("Notes")]
public class Notes
{
[Key]
public int RecordId { get; set; }
[Required]
public string RelatedTableName { get; set; }
[Required]
public int RelatedTableRecordId { get; set; }
[Required]
public string NotesText { get; set; }
}
I then have another model which could look like so:
[Table("Drivers")]
public class Drivers
{
[Key]
public int RecordId { get; set; }
[Required]
public string DriverName { get; set; }
public ICollection<Notes> DriverNotes { get; private set; }
}
There is no foreign key which links the tables. The Drivers table is linked to the Notes table by way of the RelatedTableName and RelatedTableRecordId fields.
I do not have a problem reading data from the database and hydrating the models using entity framework.
The problem I have is that I want to be able to save a new Driver and its newly created Notes in one transaction and have the RelatedTableRecordId field set to the primary key of the Driver.
If a foreign key existed entity framework would know to back fill the property but in this case it doesn't know about the relationship.
Key Points
Database Structure must not change.
Must use Entity Framework 6 Code First
Must be able to use an Execution Strategy.
Require a relationship between non key fields.
Need to be able to persist all data in a single transaction.
What I've Tried
I had a similar issue with Audit type data and solved it by doing something similar to the following (note that this is very pseudo here):
public override int SaveChanges()
{
int changes = 0;
//Disable the current execution strategy as the default ones do not support user instantiated transactions.
this.ContextConfiguration.SuspendExecutionStrategy();
try
{
//Wrap a whole transaction inside an execution strategy so that auditing can be combined with regular saving of changes.
this.ExecutionStrategy.Execute(
() =>
{
using (var transaction = this.Database.BeginTransaction())
{
//Reset the change count so that it doesn't increase each time the transaction fails.
changes = 0;
//Remove any audit records created by previous failed transactions.
this.AuditTableChanges.Local.Clear();
//Evaluate the change tracker to identify entities which will potentially require an audit trail.
var insertedEntities = this.ChangeTracker.Entries().Where(entryEntity => entryEntity.State == EntityState.Added).ToList();
//Save all changes to get identities.
changes = base.SaveChanges();
//Create the audit trail for inserted entities. This step must occur after the initial call to SaveChanges() so that the identities are set.
foreach (DbEntityEntry entryEntity in insertedEntities)
{
//For each inserted record, get the audit record entries and add them
foreach (AuditTableChange auditTableChange in GetAuditRecords(entryEntity, AuditTableChangeType.Insert).Result)
this.AuditTableChanges.Add(auditTableChange);
}
//Save the audit trail for inserted entities.
changes += base.SaveChanges();
//Commit all changes to the database
transaction.Commit();
}
});
}
finally
{
//Re-enable the execution strategy so that other calls can benefit from the retry policy.
this.ContextConfiguration.UnSuspendExecutionStrategy();
}
return changes;
}
This worked fine for the Audit data as the implementation was hidden away in the framework. I do not want my development team to have to do all of the above each time they persist records.
In its simplistic form this is as much as I'd want people to be doing:
public void CreateDriver()
{
using (MyContext context = new MyContext())
{
Drivers driver = new Drivers();
driver.DriverName = "Joe Bloggs";
Notes driverNote = new Notes();
driverNote.RelatedTableName = "Drivers";
driverNote.NotesText = "Some very long text";
driver.DriverNotes.Add(driverNote);
context.Drivers.Add(driver);
context.SaveChanges();
}
}
In a way I want a foreign key which exists in code but not in the database so that entity framework knows to fill in the RelatedTableRecordId field. I've read some articles on hacking the EDMX but this project is purely Code First only.
There are older questions on stack overflow which are similar but relate to older versions of entity framework and don't help much or have as much detail as the above.
I'm hoping that someone may have experienced a similar problem and has an answer which may involve perhaps some custom mapping/metadata or some overrides to entity framework logic.
Any help would be appreciated.
Thanks,
Greg
Any help or advice regarding this issue is greatly appreciated.
I am currently working on a project that requires a change in our data layer from a local MS SQL instance to a hosted Oracle solution.
Previously, we were using Entity Framework (Code-First) to build our data layer. I would like to take the same approach with the new data layer. We have several applications that use this library, so trying to keep the new data layer as close to the same (objects, names, etc.) as the original would be ideal. I know that Code-First is not officially supported by Oracle (a work in progress), but have read where others have had some success. Thus, for these reasons, I am attempting to do the same.
I have created my Oracle EF data layer to match as closely as I can to the original MS SQL EF data layer. The issue that I'm currently having is that when I run a query to retrieve the first or default entity from the data layer, I get the following exception:
Oracle.DataAccess.Client.OracleException: ORA-00942: table or view does not exist
If I use the exact same DbContext instance and instead run a sql query using the DbContext.Database.SqlQuery(sqlString), it works. The reason I mention this is because I've read the "table or view does not exist" error refers to a database permissions issue. That does not appear to be the case this time, since I'm using the exact same connection string in the same connection object. The only difference appears to be in using traditional sql statements versus the DbSet entities (& configurations).
My entities are relatively simple, flat objects.
public class HourlyPrice
{
public DateTime MarketDate { get; set; }
public int HourEnding { get; set; }
public string LocationId { get; set; }
public string LocationName { get; set; }
public decimal? Price { get; set; }
public int IsValid { get; set; }
public DateTime DateInserted { get; set; }
public DateTime? DateUpdated { get; set; }
}
public HourlyPriceConfiguration(string viewName)
{
ToTable(viewName);
HasKey(x => new { x.MarketDate, x.HourEnding, x.LocationName });
Property(x => x.Price).HasPrecision(13, 6);
HasEntitySetName("SourceHourlyPrices");
}
Inside my DbContext, I add the HourlyPriceConfiguration injecting the viewName ...
modelBuilder.Configurations.Add(new HourlyPriceConfiguration(this.viewName));
... and declare my IDbSet as ...
public IDbSet<HourlyPrice> SourceHourlyPrices { get; set; }
When running the code, this works ...
var sql = "select * from " + this.viewName;
var prices = db.Database.SqlQuery<HourlyPrice>(sql);
var price = prices.FirstOrDefault();
... but this ...
var price = db.SourceHourlyPrices.FirstOrDefault();
... produces the "table or view does not exist" error.
Is this just an issue with the Code-First approach, or am I missing something here? When debugging the application, I can see the viewName being passed to the configuration class is the same that is being passed to the sql statement used in SqlQuery. I've tried removing the HasEntitySetName() and changing the IDbSet to the standard HourlyPrices, but that didn't work, either.
Thanks again, in advance.
I would like to confirm that I had the same problem with a table name.
In Oracle if the name is not full UPPER CASE the table/view is not found.
Code First Automatic Migrations is limited to working with the dbo schema only.
https://community.oracle.com/thread/3622163
You can put it in beginning OnModelCreating method of your Context class as a workaround.
if (this.Database.Connection.GetType().Equals(typeof(Oracle.ManagedDataAccess.Client.OracleConnection)))
{
modelBuilder.HasDefaultSchema(new Oracle.ManagedDataAccess.Client.OracleConnectionStringBuilder(this.Database.Connection.ConnectionString).UserID);
}
The ORA-00942 exception is not a permission issue (depends on how you look at it of course); but it means that the table you are querying is not visible to your user.
You may try to explicitly set the name of your schema in your ToTable method call by using the ToTable(tableName, schemaName) implementation and see what happens.
Just wanted to add that I had the same problem after moving the DB to a different schema. I realised that it is critically to have the schema name in upper case when using ToTable(tableName, schemaName).