
Oracle.EntityFrameworkCore 8.23.50
Release Notes for Oracle Entity Framework Core 8 NuGet Package
June 2024
Oracle Data Provider for .NET (ODP.NET) Entity Framework (EF) Core is a database provider that allows Entity Framework Core to be used with Oracle databases. EF Core is a cross-platform Microsoft object-relational mapper that enables .NET developers to work with relational databases using .NET objects.
This document provides information that supplements the Oracle Data Provider for .NET (ODP.NET) documentation.
Oracle .NET Links
New Features
Bug Fixes since Oracle.EntityFrameworkCore 8.21.121
- Bug 36179457 - ORACLE EF CORE 8 ERRORS WHEN USING OPTIMIZE COMPILE OPTION
- Bug 35535281 - DEFAULT VALUE FOR NON-UNICODE COLUMN IS GENERATED WITH N PREFIX WHEN USING VALUE CONVERTER AND ENUM TYPE
- Bug 36223397 - ORA-01000 TOO MANY OPENED CURSORS EVEN WHEN DBCONTEXT IS DISPOSED
- Bug 36132873 - GUID PROPERTY RAISES A SYSTEM.NULLREFERENCEEXCEPTION
Tips, Limitations, and Known Issues
Code First
- The HasIndex() Fluent API cannot be invoked on an entity property that will result in a primary key in the Oracle database. Oracle Database does not support index creation for primary keys since an index is implicitly created for all primary keys.
- The HasFilter() Fluent API is not supported. For example, <pre>modelBuilder.Entity<Blog>().HasIndex(b => b.Url.HasFilter("Url is not null");</pre>
- Data seeding using the UseIdentityColumn is not supported.
<pre>
// C# - computed columns code sample
modelBuilder.Entity<Blog>()
.Property(b => b.BlogOwner)
.HasComputedColumnSql("\"LastName\" || '','' || \"FirstName\"");
</pre>
<pre>modelBuilder.Entity<Person>()
.UpdateUsingStoredProcedure(
"People_Update",
storedProcedureBuilder =>
{
storedProcedureBuilder.HasRowsAffectedReturnValue(true)
});</pre>
<pre>
public class MyTable
{
public int Id { get; set; }
public int? Value { get; set; }
}
</pre>
<pre>
var query = from t in context.Table
group t.Id by t.Value
into tg
select new
{
A = tg.Key,
B = context.Table.Where(t => t.Value == tg.Max() * 6).Max(t => (int?)t.Id),
};
</pre>
<pre>
SELECT "t"."Value" "A", "t"."Id", (
SELECT MAX("t0"."Id")
FROM "MyTable" "t0"
WHERE (("t0"."Value" = "t"."Id") OR ("t0"."Value" IS NULL AND
MAX("t"."Id") IS NULL))) "B"
FROM "MyTable" "t"
GROUP BY "t"."Value"
</pre>
<pre>
public class Blog
{
public int Id { get; private set; }
public string Name { get; set; }
public List<Post> Posts { get; } = new();
}
public class Post
{
public int Id { get; private set; }
public string Title { get; set; }
public string Content { get; set; }
public DateTime PublishedOn { get; set; }
}
</pre>
<pre>
var query = from blog in context.Set<Blog>().Where(c => c.Name == "MyBlog")
join post in context.Set<Post>().Where(p => p.Title == "Oracle")
on blog.Name equals post.Title
select new { blog, post };
var updateQuery = query.ExecuteUpdate(s => s.SetProperty(c => c.blog.Name, "Updated"));
</pre>
<pre>
UPDATE "Blogs" "b"
SET "b"."Name" = N'Updated'
FROM (
SELECT "p"."Id", "p"."BlogId", "p"."Content", "p"."PublishedOn", "p"."Title"
FROM "Posts" "p"
WHERE "p"."Title" = N'Oracle'
) "t"
WHERE (("b"."Name" = "t"."Title") AND ("b"."Name" = N'MyBlog'))
</pre>
<pre>
public class Author
{
public int Id { get; set; }
public string Name { get; set; }
public DateTimeOffset Timeline { get; set; }
}
</pre>
<pre>
var timeSpan = new TimeSpan(1000);
var authorsInChigley1 = context.Authors.Where(e => e.Timeline > DateTimeOffset.Now - timeSpan).ToQueryString();
</pre>
<pre>
DECLARE
l_sql varchar2(32767);
l_cur pls_integer;
l_execute pls_integer;
BEGIN
l_cur := dbms_sql.open_cursor;
l_sql := 'SELECT "a"."Id", "a"."Name", "a"."Timeline"
FROM "Authors" "a"
WHERE "a"."Timeline" > (SYSDATE - :timeSpan_0)';
dbms_sql.parse(l_cur, l_sql, dbms_sql.native);
dbms_sql.bind_variable(l_cur, ':timeSpan_0', INTERVAL '0 0:0:0.0001000' DAY(8) TO SECOND(7));
l_execute:= dbms_sql.execute(l_cur);
dbms_sql.return_result(l_cur);
END;
</pre>