RX Extension ToObservable() yields an exception when querying a nested IColletion - entity-framework

I am just trying to get comfortable with using ef and rx. Unfortunately, I came across a problem I cannot solve. I have a test database for MySQL called world.sql. EF produced the following
public worldEntities()
: base("name=worldEntities")
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
throw new UnintentionalCodeFirstException();
}
public virtual DbSet<city> city { get; set; }
public virtual DbSet<country> country { get; set; }
public virtual DbSet<countrylanguage> countrylanguage { get; set; }
I was now trying to compare "simple" Linq queries and the ToObservable() alternative which Rx provides. Using Linq I have the following query which works:
var m = new worldEntities();
var res = m.country.Where(e => e.countrylanguage.Any(i=>i.Language.Equals("German"))).Select(e => e.Name);
However I cannot figure out the Rx counterpart. If I try using the same approach
var set = m.country.ToObservable();
set.Where(e => e.countrylanguage.Any(i => i.Language.Equals("German")))
.Select(e => e.Name).Buffer(50).
Subscribe(l=>
Items.AddRange(l));
I will get an Exception with the following inner message:
{"There is already an open DataReader associated with this Connection which must be closed first."}
So my question is, how should the RX query look like, to achieve the same results.
Thanks in advance and kind regards.

Probably something like that should work:
var set = m
.country
.Where(e => e.countrylanguage.Any(i => i.Language.Equals("German")))
.Select(e => e.Name)
.ToObservable();
set.Buffer(50).
Subscribe(l=>
Items.AddRange(l));
However it is very unusual application for RX extensions and definitely not the best one to "get comfortable with".

Databases are pull-based systems. You request to pull data from a database. Rx is all about handling push-requests, not pull-requests. This is a not a good use of Rx.
If you want to learn Rx, start using it for event-handling.

Related

When to use Include in EF? Not needed in projection?

I have the following in Entity Framework Core:
public class Book {
public Int32 Id { get; set; }
public String Title { get; set; }
public virtual Theme Theme { get; set; }
}
public class Theme {
public Int32 Id { get; set; }
public String Name { get; set; }
public Byte[] Illustration { get; set; }
public virtual ICollection<Ebook> Ebooks { get; set; }
}
And I have the following linq query:
List<BookModel> books = await context.Books.Select(x =>
new BookModel {
Id = x.Id,
Name = x.Name,
Theme = new ThemeModel {
Id = x.Theme.Id,
Name = x.Theme.Name
}
}).ToListAsync();
I didn't need to include the Theme to make this work, e.g:
List<BookModel> books = await context.Books.Include(x => x.Theme).Select(x => ...
When will I need to use Include in Entity Framework?
UPDATE
I added a column of type Byte[] Illustration in Theme. In my projection I am not including that column so will it be loaded if I use Include? Or is never loaded unless I have it in the projection?
In search for an official answer to your question from Microsoft's side, I found this quote from Diego Vega (part of the Entity Framework and .NET team) made at the aspnet/Announcements github
repository:
A very common issue we see when looking at user LINQ queries is the use of Include() where it is unnecessary and cannot be honored. The typical pattern usually looks something like this:
var pids = context.Orders
.Include(o => o.Product)
.Where(o => o.Product.Name == "Baked Beans")
.Select(o =>o.ProductId)
.ToList();
One might assume that the Include operation here is required because of the reference to the Product navigation property in the Where and Select operations. However, in EF Core, these two things are orthogonal: Include controls which navigation properties are loaded in entities returned in the final results, and our LINQ translator can directly translate expressions involving navigation properties.
You didn't need Include because you were working inside EF context. When you reference Theme inside the anonymous object you are creating, that's not using lazy loading, that's telling EF to do a join.
If you return a list of books and you don't include the themes, then when you try to get the theme you'll notice that it's null. If the EF connection is open and you have lazy loading, it will go to the DB and grab it for you. But, if the connection is not opened, then you have to get it explicitely.
On the other hand, if you use Include, you get the data right away. Under the hood it's gonna do a JOIN to the necessary table and get the data right there.
You can check the SQL query that EF is generating for you and that's gonna make things clearer for you. You'll see only one SQL query.
If you Include a child, it is loaded as part of the original query, which makes it larger.
If you don't Include or reference the child in some other way in the query, the initial resultset is smaller, but each child you later reference will lazy load through a new request to the database.
If you loop through 1000 users in one request and then ask for their 10 photos each, you will make 1001 database requests if you don't Include the child...
Also, lazy loading requires the context hasn't been disposed. Always an unpleasant surprise when you pass an Entity to a view for UI rendering for example.
update
Try this for example and see it fail:
var book = await context.Books.First();
var theme = book.Theme;
Then try this:
var book = await context.Books.Include(b => b.Theme).First();
var theme = book.Theme;

How can I prevent EF7 from eagerly fixing up navigation properties?

I have an issue using EF7 in a web application with which I could use some help. I'm currently using EF7 RC1.
Here are some models that illustrate my problem.
Contact
public class Contact
{
public Guid Id { get; set; }
public string Desc { get; set; }
public ContactType ContactType { get; set; }
}
ContactType
public class ContactType
{
public Guid Id { get; set; }
public string Desc { get; set; }
public ICollection<Contact> Contacts { get; set; }
}
These models are related via Fluent API like this:
modelBuilder.Entity<Contact>(entity => {
// abridged for clarity
entity
.HasOne(c => c.ContactType)
.WithMany(ct => ct.Contacts)
.IsRequired();
});
My needs are to be able to retrieve a collection of Contact entities from the database with their ContactType property loaded. EF makes this quite easy:
using(var context = new MyDbContext()) {
var contacts = await context
.Contacts
.Include(c => c.ContactTypes)
.Where(/* some search criteria */)
.ToListAsync();
}
The issue is that in loading the ContactType properties of the Contact entities (which happens due to the call to .Include() in the query), EF also helpfully loads the Contacts property of each ContactType entity, resulting in an infinite chain of Contacts pointing at ContactTypes and ContactTypes pointing at Contacts. I understand why this is the default behavior and that it's helpful in many cases, but my needs are to serialize these entities to JSON and send them down to the client - it's a read-only situation.
My desired behavior is for EF to return a collection of Contacts with loaded (non-null) ContactType properties that have their Contacts property set to null. Is this something EF can do? Is there any way to end up with the object graph I want short of manually nulling out properties I don't want populated?
Things I've tried:
Appending .AsNoTracking() to the EF query (which doesn't seem to stop
the Contacts property of the ContactType entity from being loaded)
Telling Json.NET not to serialize infinite reference loops (which is
required to avoid infinite recursion during serialization, but still
results in a lot of extra data being serialized)
You can't avoid EF to load ContactType.Contacts collection, as it's not actually loading it but filling the collection with the loaded Contact instances.
This is why using AsNoTracking has no efect, because is not a problem of lazy loading nor ChangeTracker.
You have three possible solutions:
Use Json.NET ReferenceLoopHandling = ReferenceLoopHandling.Ignore, but as you stated it will generate lot of unnecesary data, as you will get the collection of Contacts for every ContactType
Use [JsonIgnore] attribute on ContactType.Contacts so it will be ignored by the serializer. But it will ignore it always, I don't know if you need it in other situations
Define a DTO, use something like Automapper to map your data in it (without Contacts collection) and serialize it
I would prefer the 3rd option as I don't like sending domain model objects to the client, and it avoid adding attributes to domain model not related with domain.
I have same question Entity Framework 7 Core disable auto loading
I add AsNoTracking()
IQueryable<ScheduleModel> q = _db.Schedules;
q = q.AsNoTracking();
q = q.Include(x => x.ElementItem);
q = q.Include(x => x.ScheduleHours);
Properties not populate automatic now.

Passing a comparison function and value as parameters into Entity Framework

This is a follow-up on question on Passing a comparison function as a parameter into Entity Framework.
I would like to pass a comparison function and a value into a search function that queries Entity Framework. The comparison function has to operate on different properties depending on the value. E.g., my data is
class DataItem
{
[Key]
public int ID { get; set; }
public bool Active { get; set; }
public string Prop1 { get; set; }
public string Prop2 { get; set; }
}
and I need a context method
public List<DataItem> SearchValue(Func<string, string, bool> op, string value)
{
if (value.Length < 10)
return DataItem.Where(di => di.Active && op(di.Prop1, value)).ToList();
else
return DataItem.Where(di => di.Active && op(di.Prop2, value)).ToList();
}
that I can then call like
List<DataItem> list = context.SearchValue((s1, s2) => s1 == s2, "A");
where I also need different comparison functions (all canonical).
Program compiles alright, but on running I get a "The LINQ expression node type 'Invoke' is not supported in LINQ to Entities." error.
Loading the DataItems into memory is not an option since I'll have around a billion of them. That's why I'm looking for a server-side solution. All the operations I'm using are canonical, so they can be translated into SQL queries. My question is just: how can I pass them as parameters?
This issue means that your LINQ query cannot be converted to a proper SQL query for backend execution.All LINQ to SQL or Entity framework queries get converted to SQL which is run on the backend and if they have some operation which could not be translated to SQL this error can come.
I think you should first bring your data in memory using .ToList() or .AsEnumerable() and then use 'Op' operation on that.That should solve the problem
Unfortunately you can't do it with LinqToEntities. You have to create sql query manually or call Database function...

Create an Updatable Model - Entity Framework

I just want to know if there's a way on how to create an Updatable model. Right now, I have to create procedures for insert, update, and delete for all of the tables in my model. This is very tedious so I was wondering if there is one way which I could do to resolve this?
I remember before in my previous work that we used to make models and access them (CRUD) without creating procedures. But i'm not really certain now on how it was made.
Thank you!
There are various ways in which you can automate the generation (on the fly or already generated at compile time) of the actual SQL calls to the database to insert, select, update and delete within the Entity Framework.
You can use the ORM tools (e.g. Linq to Entities) to minimise or eliminate the writing of raw SQL. This means you still have to use the correct attributes on your entities and the properties/methods therein and that's a manual process. (Some backgrounding on this MSDN page)
You can allow the framework to automatically generate your entities based on some existing database schema (only possible with SqlServer-type databases) which basically does 90% of the work for you. There may be some cases where you need to override, for example, the default insert SQL with something custom. This is achieved via the Generate Database Wizard (which I think is a part of Visual Studio 2008+).
You can use POCO classes with EF. If you're using 4.1 and above, you can use the DbContext class. To map your model to the table / columns, simply override OnModelCreating in your context class (which inherits from DbContext). Say you have a model called User, a table called Users, and the context class MyContext, the code could be smth like this:
public class User
{
public int UserId { get; set; }
public string UserName { get; set; }
}
public class MyContext : DbContext
{
public MyContext() :
base("MyContext")
{
}
public DbSet<User> Users { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<User>().
.ToTable("Users");
modelBuilder.Entity<User>().
.Property(d => d.UserId)
.HasColumnName("UserId")
modelBuilder.Entity<User>().
.Property(d => d.UserName)
.HasColumnName("UserName");
}
}
To use it, simply add the User instance to your DbSet, then call SaveChanges:
using(MyContext ctx = new MyContext())
{
var u = new User() { UserId = 1, UserName = "A" };
ctx.Users.Add(u);
ctx.SaveChanges();
}

Entity Framework and SqlDateTime overflow best practices

System.DateTime can take a wider range of values than SQL Server's DateTime. Hence there is class System.Data.SqlTypes.SqlDateTime which mimics the later.
Consequently I would have expected Entity Framework to choose SqlDateTime, but it didn't.
So my questions are...
What are the best practices to insure that your DateTime values will not cause problems when you try to save them to your database?
Is there any way of forcing EF to use SqlDateTime?
There's a number of things you can do:
if you're using SQL Server 2008 or newer, you can use the DATE or DATETIME2 data types on the database which offer the same date range as .NET's DateTime
if you can't use those new data types, it will be up to you to handle some checking / validation on your date fields before things are being stored into the persistent store. EF EntityObject offers lots of ways to tap into the process of validating and saving objects - pick one approach that works for you
More specifically, try this: http://www.vfstech.com/?p=111
Maybe this is an old thread but I will post my findings on this for the others :
Let say that we have dev env : EF 5, CodeFirst, SqlCE 4.0 :
public abstract class Entity : IEntity, IEquatable<Entity>
{
public virtual int Id { get; protected set; }
public virtual DateTime LastModified { get; set; }
[DataType(DataType.Date)]
public virtual DateTime CreatedOn { get; set; }
[DataType(DataType.DateTime)]
public virtual DateTime CreatedOn2 { get; set; }
[DataType(DataType.Time)]
public virtual DateTime CreatedOn3 { get; set; }
public virtual DateTime CreatedOn4 { get; set; }
}
with such a custom mapping :
public EntityMapping()
{
HasKey(e => e.Id);
Property(e => e.Id);
Property(e => e.LastModified).IsRequired().IsConcurrencyToken();
Property(e => e.CreatedOn).IsRequired();
Property(e => e.CreatedOn2).IsRequired();
Property(e => e.CreatedOn3).IsRequired();
Property(e => e.CreatedOn4).IsRequired();
}
This produces this, which means that we will have the overflow exception.
Changing the mappings to this while still working with SQL CE 4.0 :
Property(e => e.CreatedOn).IsRequired().HasColumnType("datetime2");
Property(e => e.CreatedOn2).IsRequired().HasColumnType("date");
Property(e => e.CreatedOn3).IsRequired().HasColumnType("date");
Property(e => e.CreatedOn4).IsRequired().HasColumnType("datetime2");
Gives this error.
Switching to SQL Server Standart 2012 seems to solve the problem ( That is not a solution for sure - just for the experiment ). The created SQL Server schema is this.
I am not an expert in Sql but it looks like to me that SQL CE does not support these dates. the problem with development env. remains. DateTime can be substituted but can bring a lot of refactoring here and tehere.
Remember also that SqlDateTime and DateTime are very different.
The solution that I find good - for the code and for the project lifecycle - is to switch between LocalDb and SQL standart as suggested by one of the links above from stackoverflow combined with custom fluentApi mapping settings to equalize model creation or both.
Introducing custom convention in EF as a safety net looks good too.
If anybody has a better all-round solution, for code and for dev-production both, post it.