Entity Framework storing arrays of data - c#

I've started playing around with using Entity Framework Code-First because it looks like a nice way to get a database up and running quickly. I'm coming from a PostgreSQL background, which has support for array types in tables, for example time[]. My question is two-fold; does SQL Server support array types, and if so, how can I use them in EF? If they're not supported, what is an alternative way to represent this data?
table Venue
openhours time[]
Edit: The array above is intended to store different times for each day of the week- a venue might have different opening hours on different weekends to weekdays, for example.

No, it is not supported, you need to store your openhours in a separate table (VenueOpenhours) with a foreign key to the Venue table.

SQL Server doesn't support array types. Extrapolating from your example schema, I think an equivalent EF POCO would be the following:
public class Venue
{
public int VenueId { get; set; }
public DateTime OpenHour { get; set; }
public DateTime CloseHour { get; set; }
}
Finding whether the Venue was open at a given time would just require a range query, Venue.Where(a => a.OpenHour <= time && a.CloseHour >= time). Of course, this is a very simplistic example. Most likely you'd want to store the Venue hours in another table. But I hope this may be able to move you in the right direction.

Related

How to linq filter on multiple GUID at once generating an appropriate sql where clause

I'm having a hard time generating a properly filtered sql query with fluent API in Entity Framework core rc2-final connected to a sqlite database.
I have the following simple entity :
public class Thing
{
[Required, Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id { get; set; }
public string Name { get; set; }
}
I need to query the database for all books that are in a stash list of Books I provide. So far, sounds easy. This is how we could write it :
// 'GetShortListFromSomewhere' returns 2 items that ALREADY exist in db
List<Thing> externalList = GetShortListFromSomewhere();
var result = db.Things.Where(thing => externalList.Contains(o.Id)).ToList();
But the following query is generated which is kind of correct and kind of .. not .. for sqlite :
SELECT "o"."Id", "o"."Name" FROM "Thing" AS "o"
WHERE "o"."Id" IN ('7edbc016-abfa-4005-83d1-b39618b047df', '2def16bb-4203-417d-847c-7bdf053a00e8')
As expected in code, this returns me 0 items although Ids are perfectly valid. Guid on Sqlite as stored on Blob and although EF-Core seems to handle the filter nicely for single item filter, it doesn't seem to handle it in this case.
How can I get around this issue knowing that I need it to be a sql operation ?
ps: Last thing I want is for EF Core to download the whole Thing collection from db and then filter it ! It would be madness in my case.
This is issue #5801. Unfortunately, it won't be fixed for the 1.0.0 release. To workaround, map the columns to byte[] properties.

Are 'heavy' aggregate functions in RavenDB advisable?

I'm working on a proof-of-concept timesheet application in C# that allows users to simply enter lots of timesheet records. The proof-of-concept will use RavenDB as storage provider, however the question below is perhaps more related to the nosql concept in general.
A user will typically enter between 1 and about 10 records each working day. Let's just say that for the sake of the discussion there will be a lot of records by the end of the year (tens or hundreds of thousands) for this specific collection.
The model for a record will be defined as:
class TimesheetRecord {
public long Id { get; set; }
public int UserId { get; set; }
public bool IsApproved { get; set; }
public DateTime DateFrom { get; set; }
public DateTime DateTill { get; set; }
public int? ProjectId { get; set; }
public int? CustomerId { get; set; }
public string Description { get; set; }
}
Logically, the application will allow the users, or project managers, to create reports on the fly. Think of on the fly reports like:
Total time spent for a project, customer or user
Time spent for a project, or customer in a certain time span like a week, month or between certain dates
Total amount of hours not approved already, by user - or for all users
Etc.
Of course, it is an option to add additional fields, like integers for weeknumber, month etc. to decrease the amount of crunching needed to filter on date/period. The idea is to basically use Query<T> functions by preference in order to generate the desired data.
In a 'regular' relational table this all would be no problem. With or without normalization this woulb be a breeze. The proof-of-concept is based on: will it blend as well in a nosql variant? This question is because I'm having some doubts after being warned about these 'heavy' aggregate functions (like nested WHERE constraints and SUM etc.) not being ideal in a document store variant.
Considering all this, I have two questions:
Is this advisable in a nosql variant, specifically RavenDB?
Is the approach correct?
I can imagine storing all the data redundantly, instead of querying on the fly, would be more performant. Like in adding hours spent by a certain user in a Project() or Customer() object. This, however, will increase complexity with updates considerably. Not to mention create immense redundant data all over the collections, which on its turn seems like a direct violation of seperation of concern and DRY.
Any advise or thoughts would be great!
I'm a big fan of RavenDB, but it is not a silver bullet or golden hammer. It has scenarios for which it is not the best tool for the job, and this is probably one of them.
Specifically, document databases in general, and RavenDB in particular, aren't very applicable when the specific data access patterns are not known. RavenDB has the ability to create Map/Reduce indexes that can do some amazing things with aggregating data, but you have to know ahead of time how you want to aggregate it.
If you only have need for (let's say) 4 specific views on that data, then you can store that data in Raven, apply Map/Reduce indexes, and you will be able to access those reports with blazing speed because they will be asynchronously updated and always available with great performance, because the data will already be there and nothing has to be crunched at runtime. Of course, then some manager will go "You know what would be really great is if we could also see __." If it's OK that manager's request will require additional development time to create a new Map/Reduce index, UI, etc., then Raven could still be the tool for the job.
However, it sounds like you have a scenario with a table of data that would essentially fit perfectly in Excel, and you want to be able to query that data in crazy ways that cannot be known until run time. In that case, you are better off going with a relational database. They were created specifically for that task and they're great at it.

How to insert an ObservableCollection property to a local sqlite-net db?

I have a quick question about the sqlite-net library which can be found here : https://github.com/praeclarum/sqlite-net.
The thing is I have no idea how collections, and custom objects will be inserted into the database, and how do I convert them back when querying, if needed.
Take this model for example:
[PrimaryKey, AutoIncrement]
public int Id { get; set; }
private string _name; // The name of the subject. i.e "Physics"
private ObservableCollection<Lesson> _lessons;
Preface: I've not used sqlite-net; rather, I spent some time simply reviewing the source code on the github link posted in the question.
From the first page on the sqlite-net github site, there are two bullet points that should help in some high level understanding:
Very simple methods for executing CRUD operations and queries safely (using parameters) and for retrieving the results of those
query in a strongly typed fashion
In other words, sqlite-net will work well with non-complex models; will probably work best with flattened models.
Works with your data model without forcing you to change your classes. (Contains a small reflection-driven ORM layer.)
In other words, sqlite-net will transform/map the result set of the SQL query to your model; again, will probably work best with flattened models.
Looking at the primary source code of SQLite.cs, there is an InsertAll method and a few overloads that will insert a collection.
When querying for data, you should be able to use the Get<T> method and the Table<T> method and there is also an Query<T> method you could take a look at as well. Each should map the results to the type parameter.
Finally, take a look at the examples and tests for a more in-depth look at using the framework.
I've worked quite a bit with SQLite-net in the past few months (including this presentation yesterday)
how collections, and custom objects will be inserted into the database
I think the answer is they won't.
While it is a very capable database and ORM, SQLite-net is targeting lightweight mobile apps. Because of this lightweight focus, the classes used are generally very simple flattened objects like:
public class Course
{
public int CourseId { get; set; }
public string Name { get; set; }
}
public class Lesson
{
public int LessonId { get; set; }
public string Name { get; set; }
public int CourseId { get; set; }
}
If you then need to Join these back together and to handle insertion and deletion of related objects, then that's down to you - the app developer - to handle. There's no auto-tracking of related objects like there is in a larger, more complicated ORM stack.
In practice, I've not found this a problem. I find SQLite-net very useful in my mobile apps.

Specify decimal scale as an attribute using EF code first

I'm using Entity Framework Code First to query my SQL Server database. I'm also using code migrations to keep it up to date.
When I use the decimal type, the underlying columns are created with a precision/scale of 18,2. For one particular column (exchange rate) I would like to increase this to 18,6.
I'd like to add an attribute to my class that will instruct EF to use the specified decimal precision, as in the following example :
public class Transaction
{
[Key]
public int ID { get; set; }
...
[DisplayName("Exchange Rate")]
[DecimalPrecision(18, 6)]
public decimal? ExchangeRate { get; set; }
}
What I do not want to do is update the OnModelCreating function as suggesting in this question
Over here I found a potential solution, but I then discovered that code won't compile as it is based on pre-release functionality that was then removed.
An alternative is proposed here, but that looks way complicated, and perhaps before I wade in I thought I might ask if an alternative exists? EF is moving so fast it's hard to keep up with the evolutions, perhaps I missed something.

Representing a tinyint field as an enum in Entity Framework

I've been using Linq2Sql for the last few years and got used to a few features, like having an int or tinyint field in the DB, that I redefine in the DBML file to be of enum type, so it's nice and convenient to run a SQL query directly comparing to the enum (see here for my question 3 years ago on the subject, and the answer there).
Now I'm starting a project using Entity Framework 5, and while EF seems to have gotten many things right that L2S didn't (e.g. detach/reattach), I'm dismayed to see that there doesn't seem to be any easy way to change the C# type of such a field to be an enum.
Has anyone found a way to do this cleanly, so that I could have a query like:
var q = entities.Things.Where(t => t.Status == TStatus.Closed);
(and no, I don't want to have to cast to int or byte inline).
Code First
EF5 Code First supports enum properties on .NET 4.5. The following entity will create a int field in the database:
public class Event
{
public int EventId { get; set; }
public Status Status { get; set; }
}
public enum Status
{
Open,
Closed,
Pending
}
To which you could query:
db.Events.Where(e => e.Status == Status.Pending)
Database First
As explained in this post, here's how you accomplish the same thing for Database First.
Go to the model browser and create a new enum type, then go to whatever column you wish to use it on and change its type to the enum that you just created.

Categories

Resources