Posts Tagged ‘Databases in general’
Scott Guthrie recently posted article about New Embedded Database Support with ASP.NET. This made me think about other options, Firebird in particular, and advantages and disadvantages. What I’m going to do is to very shortly introduce Firebird Embedded here and then compare it with features Scott wrote in his article.
Firebird Embedded, shortly, is Firebird database server in one DLL. No need to install etc., just load this DLL and use it. To be precise, there are some other DLLs, i.e. to support national charsets, but it’s still in under 10MB all. The database itself is built from same sources as “full” server and it’s not limited in any way.
Works with Existing Data APIs – as I said, Firebird Embedded is based on same codebase as “full” server, thus the SQL and API is same. And not only this, the ADO.NET provider for Firebird works with it and you’re programming using same thinking.
No Database Installation Required and Database Files are Stored on Disk – databases created by Firebird Embedded are stored wherever you want, with any extension. Firebird itself doesn’t have any master database, thus even the “full” server works with any (valid database) file.
Shared Web Hosting Scenarios Are Now Supported with SQL CE 4 – sure you don’t need to install anything with Firebird Embedded, that’s why it’s called Embedded. And not only this, from version 2.5, you can open database from different processes, i.e. IIS worker process and Apache workers or some console application doing something in background.
Visual Studio 2010 and Visual Web Developer 2010 Express Support – as the tool set for Firebird Embedded is exactly same as for “full” Firebird, you can use DDEX (aka Server Explorer support), Entity Framework (LINQ), …
Supports Both Development and Production – this is something I’m silently expecting. But yes, you can do the same with Firebird Embedded too.
Easy Migration to SQL Server – ahh, my favorite point. The Firebird Project has of course whopping number of tools to support migration from Embedded to “full”. The most used is … nothing. The databases are fully compatible and you can switch servers without any other tools, migration, conversion, … Just place it where you want it and connect to it, either with “full” or Embedded Firebird. And to switch your application? Again nothing. Same ADO.NET provider, just change connection string, if needed. Mostly you’ll add server IP address and maybe different path and manually switch server type, if you want. Really the migration is so simple. It is one minute task and thanks to same tool set, no matter what you version your targeting during development, your application will work with the other as well without any additional effort.
You like Firebird Embedded? I do, a lot. SQL Server Compact Edition 4 looks promising, but Firebird has something to offer as well. And recall, it’s based on same sources as “full” Firebird, very mature codebase, examined with tons of installations.
The EDM designer in Entity Framework 4 has a “nice” new feature. You, know in EFv1 you was forced to map all three CUD procedures or nothing. If you didn’t do that, the validation feature told you. If you do the same in EFv4 the validation succeeds. Great, you may think. Finally I can use just procedures I really want (if you whatsoever want to use SPs and tight the logic into database when using ORM) to use and the rest will be generated for me. But nope. In fact the error will be thrown in runtime(!!!).
It’s described in documentation. But I couldn’t help but wonder, who did this decision??? I hate every error in runtime, I like my static compile time checking. It’s much safer, in my opinion.
I don’t know whether it’s somewhere specifically pointed, but the ObjectContext in Entity Framework v4 has two (three) new handy methods. And I like these.
It’s kind of escape hatch similar to DefiningQuery. First method is Translate<T>. It takes DbDataReader and materializes the data back into entities. It’s similar to Materialize method from EFExtensions. If you some code in pure ADO.NET and you don’t have time or resources to redo it in EF (or it’s way easier old way) you can rewire the result into existing objects. I like it. Whenever I’ll feel I need to get dirty (and probably due to performance reasons) I can do it pretty easily.
using (testovaciEntities ent = new testovaciEntities())
{
IDbConnection conn = (ent.Connection as EntityConnection).StoreConnection;
conn.Open();
using (IDbCommand cmd = conn.CreateCommand())
{
cmd.CommandText = "select * from master";
using (DbDataReader reader = (DbDataReader)cmd.ExecuteReader())
{
MASTER[] result = ent.Translate(reader).ToArray();
Console.WriteLine(result.Length);
}
}
}
The other method is similar and simplifies the process of getting dirty if you simply need to run you fine tuned query with neat and sexy constructs.
It’s ExecuteStoreQuery<T>. This method simply allows you to run any sql command directly in store language (thus you can use all features your database offers) and fetch and materialize back resulting entities. Similar to this is ExecuteStoreCommand which is similar to ExecuteNonQuery from pure ADO.NET. But you can do this without the method easily too, the method is just more convenient.
BTW also note that the Translate method isn’t adding the entities into context, it’s just about fetching and materializing.
Yesterday there was a question in one list I’m following. Simply to share some recommendation for tool being able to reverse engineer the database structure and show some E-R diagram.
After I get time to reply with some suggestions, idea came to my head. The EDM designer is actually kind of reverse engineering tool. Did you realized that?
As the EF support for major database platforms is available it’s easy to get a basic overview of the database structure without leaving Visual Studio. Sure it doesn’t have some cool features of specialized programs, but on the other hand it’s already in VS (Express edition is free) and you don’t have to buy and install another product (if you’re not doing this often, but then you’re probably using the specialized program).
From time to time I have to run two or more queries that I know will always be two or more – like some first/skip records and also total count. If you write it as two queries and execute, that means two round trips to database. Although it may not matter if the network latency is very small, why not to challenge myself and try to find some workarounds.
Sure you can create some stored procedures and get the data back from these, but I was thinking about more LINQ to Entitiesish way. I recalled a way I one time used inside one project. Although it was done in pure SQL, it, as it turned out, works, kind of, for LINQ to Entities as well.
The idea is using “one row table” and put the queries as columns. Let me demonstrate:
select
(select foo, bar from table1 where ...),
(select baz, foo from table2 where ...)
from OneRowTable;
Where the OneRowTable can be specially created table or i.e. for Firebird RDB$DATABASE or for Oracle Database dual. It isn’t the nicest SQL (and also challenges optimizer), but works. In columns as queries you can put anything you want as long as it is syntactically correct.
OK, what about the Entity Framework or LINQ to Entities respectively. I created the “one row table” first:
create table OneRowTable(x bit primary key);
insert into OneRowTable values (0);
The table needs to have the primary key to be able to import it into entity model, the datatype doesn’t matter (I was using MS SQL, hence the bit).
What about the queries? Similar approach:
var allinone = context.OneRowTable.Select(_ => new
{
AData = context.a.Where(a => a.x.HasValue && a.x.Value > 10).Select(a => new { A1 = a.id, A2 = a.id * 2 }),
BData = context.b.Where(b => b.id < 999).Select(b => new { B1 = b.id, B2 = b.y }),
});
string query = (allinone as ObjectQuery).ToTraceString();
var data = allinone.First();
var adata = data.AData;
var bdata = data.BData;
The a and b are my testing tables. You can check there’s only one query executed. Encapsulating this into some method is only piece of cake.
And how the query looks like? Well for my MS SQL test:
SELECT
[UnionAll1].[x] AS [C1],
[UnionAll1].[C2] AS [C2],
[UnionAll1].[C1] AS [C3],
[UnionAll1].[id] AS [C4],
[UnionAll1].[id1] AS [C5],
[UnionAll1].[C3] AS [C6],
[UnionAll1].[C4] AS [C7],
[UnionAll1].[C5] AS [C8],
[UnionAll1].[C6] AS [C9]
FROM (SELECT
[Project1].[C2] AS [C1],
[Extent1].[x] AS [x],
1 AS [C2],
[Project1].[id] AS [id],
[Project1].[id] AS [id1],
[Project1].[C1] AS [C3],
CAST(NULL AS int) AS [C4],
CAST(NULL AS int) AS [C5],
CAST(NULL AS varchar(1)) AS [C6]
FROM [dbo].[OneRowTable] AS [Extent1]
LEFT OUTER JOIN (SELECT
[Extent2].[id] AS [id],
[Extent2].[id] * 2 AS [C1],
1 AS [C2]
FROM [dbo].[a] AS [Extent2]
WHERE ([Extent2].[x] IS NOT NULL) AND ([Extent2].[x] > 10) ) AS [Project1] ON 1 = 1
UNION ALL
SELECT
2 AS [C1],
[Extent3].[x] AS [x],
[Extent4].[id] AS [id],
CAST(NULL AS int) AS [C2],
CAST(NULL AS int) AS [C3],
CAST(NULL AS int) AS [C4],
[Extent4].[id] AS [id1],
[Extent4].[id] AS [id2],
[Extent4].[y] AS [y]
FROM [dbo].[OneRowTable] AS [Extent3]
CROSS JOIN [dbo].[b] AS [Extent4]
WHERE [Extent4].[id] < 999) AS [UnionAll1]
ORDER BY [UnionAll1].[x] ASC, [UnionAll1].[C1] ASC
Not exactly the original shape. The translator took another way creating two one row results and using union all to get it into one query. Except this, the query is in general the same (the explicit joins are as result same as the subselects, though little bit more confusing in this case).
Again, this isn’t general purpose way of doing it and may result in worse performance than running queries separately and I would recommend using it only after careful testing and on controlled limited set of queries.
Today I uncovered a magic command from Entity Framework v4 when you create M:N association and the underlying table is defined with both columns as identity and you insert there. I don’t what’s it good for, as this table in fact only stores the two IDs to connect other tables. But somebody may build some logic on identity there, sure.
When I first saw the command, I was completely stunned. I had no idea what’s going on there and whether I see there one or more commands. You can have fun too:
declare @generated_keys table([ID_A] int, [ID_B] int)
insert [dbo].[A_B]
output inserted.[ID_A], inserted.[ID_B] into @generated_keys
default values
select t.[ID_A], t.[ID_B]
from @generated_keys as g join [dbo].[A_B] as t on g.[ID_A] = t.[ID_A] and g.[ID_B] = t.[ID_B]
where @@ROWCOUNT > 0
As an old school guy I was first looking for semicolons and then later tried to decode it by “parsing” the content.
Isn’t it nice…
Today I seen a code with good chance of hard to find mysterious bugs. Let’s start with database table structure we’re going to use for demonstration.
create table NullTest(id int primary key, b bit);
insert into NullTest values (0, 1);
insert into NullTest values (1, 0);
insert into NullTest values (2, null);
If you now try to query this table via LINQ (i.e. LINQ to Entities) you may get surprising results.
foreach (var item in ent.NullTests.Where(x => x.b != true))
{
Console.WriteLine(string.Format("ID: {0} t B: {1}", item.id, item.b));
}
Console.WriteLine("===");
foreach (var item in ent.NullTests.AsEnumerable().Where(x => x.b != true))
{
Console.WriteLine(string.Format("ID: {0} t B: {1}", item.id, item.b));
}
If you run this code, you’ll get different results.
ID: 1 B: False
===
ID: 1 B: False
ID: 2 B:
What happened? Is the database engine doing something wrong? Or is there a bug in LINQ? Neither of those. In fact both results are correct. The second one (evaluated in .NET on client) is obvious why it’s as is. But what happened in processing of first one (evaluated on database side)? The devil is in NULL logic. Every operation with NULL results in NULL or false if it’s a boolean operation. And this exactly explains the inconsistent result. In .NET null != true is true but in databases it’s false (because of the NULL rules described above).
Thus if you’re writing LINQ query for database, although the impedance mismatch should be hidden from you when using LINQ, you need to take into account different NULL handling in database engines and in .NET (or any common programming language).
Remember the DBNull.Value? That was explicit solution for this “problem”.
When I first heard about exposing foreign keys in conceptual model I was getting crazy. It’s the object world, you shouldn’t think this way, in a relational world. On the other hand, working purely in objects can be a pain, especially in web development, and performance problem. Sure, foreign keys can solve you some “problems” (and maybe add some) without tweaking the EntityKey or doing stub entities. Which is hard when dealing with POCO.
But is this a really way to go? Exchange cleanness for comfort.
I don’t know. I was doing the EntityKey magic, and it was magic, because it was not clean. Now I can do it easily, but. For POCO it’s harder, as there’s no EntityKey, but again, you have plain objects – why to deal with foreign keys? What if you move to some non-relational store?
But still one piece is left. The M:N association. Here I cannot use any foreign key, so it’s back to hacking or pure objects. And maybe this is the point. If creating some kind of comfort here for developers, why not to find some way for complete story? Wouldn’t it be nice?
Now I know (see how good is trying to write your own ideas). I don’t like the current concept of FKs. It’s too easy, and just too replicating behavior of relational world. But if there would have been some improvement for the other types of associations to cover all types in uniform way, I would vote for it with both my hands. Although still saying that it’s not nice but acceptable, as relational databases – it seems – will be with us for sure next couple of years.
Next Firebird conference is coming. This year in München, Germany. I’ve never been in München though it’s pretty close to Czech Rep. thus I’m looking forward.
You can find info about conference at firebird-conference.com. I’ll be speaking there too, hence if you’re interested in Firebird and .NET you should definitely come. Every day I have one session. I’ll be covering new (2.5+) protocol implementation in .NET client for Firebird 2.1, Entity Framework support (also new in 2.5) and finally you’ll see how to create Windows phone (formely PocketPC, …) application and accessing Firebird database.
And the conference will be also great place to meet people you know from list etc. and talk face to face about your Firebird related problems, challenges and solutions. If you have any specific need to show (related to my three sessions) feel free to drop line in comments.
I have a strong feeling that MS SQL knows I don’t like it. I don’t say it’s a bad database, but sometimes it’s really “interesting”.
OK, so what I faced this time? Let’s start with basic facts. The NULL value in database is a special value. NULL and NULL is again NULL, NULL and False is again NULL and NULL isn’t equal to NULL. Two days ago I was creating a chain of records in database (which isn’t too relationalish, but …) and I needed unique constraint on one column. No problem you may think. So did I. But not in MS SQL.
Check this example:
1> create table test(id int primary key, foo int);
2> create unique index idx_text on test(foo);
3> go
1> insert into test values (1, null);
2> go
(1 rows affected)
1> insert into test values (2, null);
2> go
Msg 2601, Level 14, State 1, Server X2-001SQLEXPRESS, Line 1 Cannot insert duplicate key row in object 'dbo.test' with unique index 'idx_text '.
The statement has been terminated.
What a mess! Looks like somebody in MS SQL engine team thinks NULL == NULL. After some railing, testing on Firebird and asking my friend about Oracle, I googled: https://connect.microsoft.com/SQLServer/feedback/ViewFeedback.aspx?FeedbackID=299229. Looks like I’m not alone; feeling better. 
Luckily I’m working on MS SQL 2008 and I can use filtered indices. Created unique index with where clause where <column> is not null and I’m done. But boy that was a bitter finding. Hope I’ll not be punched to the face with these basics again in an at least two months.
I hate transactions, ACID and all the stuff. Really, I do. No, I don’t, it’s a great to have challenges with this kind of thinking. But in last two projects (in a row) I had similar problem and transactions were making it even more challenging.
The simple version is that I needed to have data constraint in database (did I mention that I’m constraint freak?) based on not the row itself, but the data in the table and related tables. If you’ve play with transactions you know this is a problem. Either you may run in read uncommitted mode, see everything and if somebody will do something violating the constraint, even if it will be rolled back, you will start screaming and throwing exceptions or you will use serializable and, to be sure, explicit locking in every piece of trigger or stored procedure code, which is good for you but not for performance. Choose whatever fits your needs better, but right now, for this particular scenario I wish the transactions gone and pretending there’s no isolation from others at all (and with decent performance too).
I know it’s impossible, because interactions in database are making creating some general purpose “command/constraint” tough. And what’s good for one case is definitely not suitable for other.
Anyway maybe with more work done on distributed systems and clouds, where even the simple constraints are interesting to enforce, we’ll find some good way how to solve this.
When you write huge (I mean really huge, not a ~300 lines baby) complex query you may experience, that the generated query looks (well) suboptimal. The reason is that after some line the Entity Framework will gave up on optimization and simply throws it as is. To turn this off and force to simplify it whatever query it is you can add this into your app.config, as Kati Iceva pointed in MSDN forums.
<system.diagnostics>
<switches>
<add name="System.Data.EntityClient.IgnoreOptimizationLimit" value="1" />
</switches>
</system.diagnostics>
But also take into account that this may end up with a significant time spent in EF’s code and at the end the query will be still too big for the store to run it or the store would do better job optimize it. Thus the overall time may be same or even worse (= use carefully).
It’s also worth, if you’re able to write the query a lot simpler, to discuss this in MSDN forums, so the code in EF can be improved.
Julie Lerman made a great post about The cost of eager loading in Entity Framework. And everything there is true, in fact if you take my Entity Framework training, you will know that with all reasons and you’ll also learn performace improvements you may incorporate into your solution.
I want to make some small addition to this post. There’s another stuff to think about. That’s the cost of processing query on server.
You should always consider the cost of parsing, compiling, finding execution plan etc. the query on server as well as fetching the intermediate data (which may cause cleaning up caches etc.). Thus sometimes (and we’re back to balance as Julie said) it’s better to issue couple of smaller (not so complex) queries, rather than one huge query.
If you want to map stored procedure you have three options what the stored procedure can return. Nothing, some scalar value and entity. The problem is that sometimes you have SP that’s returning some data, but not some entity. The way to solve this is to create entity with same shape as the SP is returning. But the problem is, that this entity type needs to be mapped to something, probably table. Else the model is not valid. The good message is, that you can create fake table in SSDL and use it.
But it’s a pain to create it, because you have to deal with XML directly and create not only the fake table with proper structure, but also entity set. When reading pre-prelease
version of Julie Lerman‘s wonderful book Programming Entity Framework there was a sigh about some tool to automate the process. Well today I have some time, to create rough tool to create some kind of this tool.
static void Main(string[] args)
{
#region Initial checking
if (args.Length != 3)
return;
string tablenameToFake = args[0];
string emdxFile = args[1];
string fileForSaving = args[2];
if (!File.Exists(emdxFile))
return;
if (File.Exists(fileForSaving))
return;
#endregion
XDocument xdoc = XDocument.Load(emdxFile);
const string CSDLNamespace = "http://schemas.microsoft.com/ado/2006/04/edm";
const string SSDLNamespace = "http://schemas.microsoft.com/ado/2006/04/edm/ssdl";
XElement csdl = xdoc.Descendants(XName.Get("Schema", CSDLNamespace)).First();
XElement ssdl = xdoc.Descendants(XName.Get("Schema", SSDLNamespace)).First();
XElement csdlItem = csdl.Elements(XName.Get("EntityType", CSDLNamespace))
.Where(x => x.Attribute("Name").Value.ToUpperInvariant() == tablenameToFake.ToUpperInvariant()).FirstOrDefault();
if (csdlItem == null)
return;
Func<string, string> getStoreType = (string csdlTypeName) =>
{
// Use some information from store provider or use some dummy or extend this switch using common SQL names?
switch (csdlTypeName)
{
case "Int16":
case "Int32":
case "Int64":
return "int";
case "String":
return "varchar";
default:
return "blob";
}
};
#region New EntityType creation
XNamespace n = SSDLNamespace;
XElement tableToFake = new XElement(n + "EntityType", new XAttribute("Name", tablenameToFake));
var keys = from x in csdlItem.Element(XName.Get("Key", CSDLNamespace)).Elements(XName.Get("PropertyRef", CSDLNamespace))
select new XElement(n + "PropertyRef",
new XAttribute("Name", x.Attribute("Name").Value));
tableToFake.Add(new XElement(n + "Key", keys.ToArray()));
var columns = from x in csdlItem.Elements(XName.Get("Property", CSDLNamespace))
select new XElement(n + "Property",
new[] {
new XAttribute("Name", x.Attribute("Name").Value),
new XAttribute("Type", getStoreType(x.Attribute("Type").Value)),
new XAttribute("Nullable", (x.Attribute("Nullable") != null ? x.Attribute("Nullable").Value : "true"))
});
tableToFake.Add(columns.ToArray());
#endregion
#region EntitySet for new entity
XElement someEntitySet = ssdl.Element(XName.Get("EntityContainer", SSDLNamespace)).Element(XName.Get("EntitySet", SSDLNamespace));
XElement newEntitySet = new XElement(someEntitySet);
newEntitySet.Attribute("Name").Value = tablenameToFake;
newEntitySet.Attribute("EntityType").Value = ssdl.Attribute("Namespace").Value + "." + tablenameToFake;
#endregion
ssdl.Add(tableToFake);
ssdl.Element(XName.Get("EntityContainer", SSDLNamespace)).Add(newEntitySet);
using (XmlTextWriter writer = new XmlTextWriter(fileForSaving, Encoding.Default))
{
xdoc.WriteTo(writer);
}
}
This code simply looks for entity you specified and makes the appropriate items in SSDL. It’s very rough, especially datatypes for table are scamped
, but you can extend it youself with your favourites. Or maybe better use some information from store provider. Anyway the basic idea is here, if you extend dataypes, it will work well for this stuff. Mapping should be done by you in designer, although because column names are same as entity’s, you only need to choose right table name, rest will be done by the designer. And of course, when updating model from database, these changes are lost.
Comments are welcome.
I’m pleased to announce 2.5.0 Beta 1 for .NET 3.5/2.0 [with Entity
Framework support] version. It contains several bugfixes as well as
brand new Entity Framework support (still beta!). Looking forward to
your feedback.
Binary as well as sources can be downloaded from
http://www.firebirdsql.org/index.php?op=files&id=netprovider.
Today there was a question in db section in builder.cz forum. In essence, how to show people having birthday today or in couple of days if I have a birthdate. Well the solution I’ll show you here is in Firebird syntax, but shouldn’t be a problem to rewrite it to any other platform you like.
So the solution is like this (of course, you can find many other ways how to solve it):
select dateadd(year, datediff(year, birthdate, current_date), birthdate) from
(
select cast('1.2.1993' as date) as birthdate from rdb$database
);
OK, what’s the idea behind. First step is to get difference between these dates in year. Then, using the dateadd function to prevent some mismatch in date arithmetics (i.e. leap years), to add this difference to birthdate. Now you have it in “current year”, so it’s easy to test whether it’s between today and today + x. To improve speed, you can create computed index for this expression.
Today I had some time and I spent it playing with associations mapping on custom objects. Adding new objects is easy. It’s what you already know. The only one new part is work with associations and navigation properties. But as always when you stuck you can generate dummy EDMX file and look at the result.
You can start from scratch and create all classes and so on as in previous article. But I’ll start where I ended, it’s little bit faster.
First thing you have to create is new class, related to our Product class. I’ll create ProductSize class that will hold info about the size of product (don’t try to find something useful on this, it’s just a simple example). The class will contain only ID and Size property. You can take inspiration from previous article, it’s almost same. What you have to add is an IEntityWithRelationships interface implementation to both classes. It’s same for both. This interface forces you to implement RelationshipManager member.
RelationshipManager IEntityWithRelationships.RelationshipManager
{
get
{
if (_relationships == null)
_relationships = RelationshipManager.Create(this);
return _relationships;
}
}
Now you have to either edit CSDL, MSL and SSDL files by hand (if your night reading is some *.edmx file) or generate these again using EdmGen/EdmGen2 and remove any unnecessary lines. Also you can rename some items to match your needs and class members (i.e. if you have NavigationProperty one-to-many on one side would be probably plural and on other side singular). Good checkpoint after this is to run EdmGen with ValidateArtifacts mode to uncover any problems.
After this you have to modify class that you get in previous article from custom tool usage. You have to apply EdmRelationshipAttribute using the assembly prefix, because it has AttributeTargets.Assembly as usage. When you use custom tool, it will be generated for you. When first trying to do the mapping I forgot about it and I lost half an hour of my time.
[assembly: EdmRelationship("CustomClasses_EDM", "FK_Products_ProductSizes", "ProductSizes", RelationshipMultiplicity.One, typeof(CustomClasses_EDM.ProductSize), "Products", RelationshipMultiplicity.Many, typeof(CustomClasses_EDM.Product))]
Now you only need to add navigation properties in your custom classes. Of course, you can add some properties to your ObjectContext class, similar to Products.
OK, first, apply EdmRelationshipNavigationProperty attribute to your navigation properties. For my Product object and ProductSize property it looks like this.
[EdmRelationshipNavigationProperty("CustomClasses_EDM", "FK_Products_ProductSizes", "ProductSizes")]
Let’s do the getter. You have to get RelationshipManager and use GetRelatedReference method. For my Products ⇒ ProductSizes direction you should end up with:
get
{
return ((IEntityWithRelationships)(this)).
RelationshipManager.
GetRelatedReference<ProductSize>("CustomClasses_EDM.FK_Products_ProductSizes", "ProductSizes").Value;
}
For other direction use the GetRelatedCollection method and no Value is used. The setter for Products ⇒ ProductSizes direction is just about assigning value to Value. For ProductSizes ⇒ Products it’s little bit different. You have to use InitializeRelatedCollection method to set new value.
((IEntityWithRelationships)(this)).
RelationshipManager.
InitializeRelatedCollection<Product>("CustomClasses_EDM.FK_Products_ProductSizes", "Products", value);
And maybe it’s good idea to check for nulls, because it’s not allowed to put it there (again, just fine-tuning).
Now when you try to run the code like:
var q = from p in ctx.Products
where p.ID < 200
select p;
foreach (Product p in q)
{
Console.WriteLine(p.Name);
Console.WriteLine("t" + p.ProductSize.Size);
}
You got exception. Yeah, lazy loading. You have to use, for example (Entity Framework Include with Func):
var q = from p in ctx.Products.Include("ProductSize")
where p.ID < 200
select p;
foreach (Product p in q)
{
Console.WriteLine(p.Name);
Console.WriteLine("t" + p.ProductSize.Size);
}
Using custom objects and associations with Entity Framework isn’t hard too. You generate three files from database, change it (which is maybe the hardest part – to match database to your objects) and small changes in objects. And you’re done.
Yet again, with POCO and persistence ignorance it will much easier. But it isn’t impossible now.
See also: How to map your custom objects in Entity Framework
Published on Databazovy Svet
Well, generating EDMX file from database and letting Visual Studio to generate all the objects is easy. But sometimes you have your custom objects with custom logic. How to solve this? In version 1 of Entity Framework this isn’t easy. It’s possible, but not easy. The good news is, that for version 2 there is huge amount of work on POCO (Plain Old CLR Objects) with persistence ignorance.
With current version you have, in general, two possible choices. The “easier” way is to derive from special object EntityObject. Anyway, this is probably what you don’t want, because you’re probably deriving from your own objects (and as we know multiple inheritance isn’t possible in C#). The other way is to implement some interfaces. It’s not so straightforward, but, at least in my opinion, more practical.
In our simple example we’ll be neither using complex types (it’s not so hard to add it) nor any associations (I’ll cover this later in other article). Let’s start with our class, I’ll call it Product and it’ll be very simple.
public class Product
{
private int _id;
private string _name;
private int _price;
public int ID
{
get { return _id; }
set { _id = value; }
}
public string Name
{
get { return _name; }
set { _name = value; }
}
public int Price
{
get { return _price; }
set { _price = value; }
}
}
As you can see, the class is really simple. You can imagine some logic i.e. on price or on name length. To make this object “tasty” for Entity Framework infrastructure you have to implement only one interface. It’s called IEntityWithChangeTracker. For associations support you should implement also IEntityWithRelationships. There’s also IEntityWithKey interface that forces you to implement EntityKey to improve performance and decrease memory usage. It’s just cherry on a pie.
The first noted interface implementation is pretty easy. You’ll just implement one method in easy way.
void IEntityWithChangeTracker.SetChangeTracker(IEntityChangeTracker changeTracker)
{
_changeTracker = changeTracker;
}
With complex types you have also set change tracker for these using SetComplexChangeTracker method.
To make change tracker working, we need to slightly change our setters. The setters should look like this for Name property.
set
{
if (_changeTracker != null)
_changeTracker.EntityMemberChanging("Name");
_name = value;
if (_changeTracker != null)
_changeTracker.EntityMemberChanged("Name");
}
Pretty simple, isn’t it? The last thing you have to change in your class is to add EdmScalarProperty attribute to ID, Name and Price members. That’s all you have to do with the class.
Now comes the tricky part (don’t be scared it’s not heavy magic
). First you need to get SSDL, MSL and CSDL files. These files contain store-schema, mapping and conceptual-schema definition. Although you can write these files by hand, using some tool is much faster. The easiest way is to generate these using EdmGen (or maybe EdmGen2). EdmGen is standard part of Entity Framework. Just use FullGeneration mode and provide /connectionstring and /project parameters. This gives you five files in result. Delete the two with *.cs extension, you don’t need it. With EdmGen you get complete mapping for whole database so you have to delete some unnecessary stuff. Leave there only lines related to Products table (or whatever your table named is). If you don’t understand content of these files, the best way is to generate *.edmx file in Visual Studio only for our table and look at the result (EDMX file is in fact just CSDL, MSL and SSDL together plus some other stuff. You can use i.e. EdmGen2 to extract these files. But EdmGen2 isn’t standard part of Entity Framework.) right-clicking on the file and choosing Open With... and XML Editor. After this tricky part add these files to your project. On CSDL file open Properties and use for Custom Tool EntityModelCodeGenerator. This generates you new file under CSDL file. Copy content into new file and remove the Custom Tool definition. This new file contains implementation of ObjectContext class and also Products class. You can delete Products class (or class for your table), because we have ours. The last step is to replace occurrences of Products that has been removed, by Product, which is our class (you can use Products (plural), where it makes sense, of course). So the result can look like this.
public global::System.Data.Objects.ObjectQuery<Product> Products
{
get
{
if ((this._Products == null))
{
this._Products = base.CreateQuery<Product>("[Product]");
}
return this._Products;
}
}
private global::System.Data.Objects.ObjectQuery<Product> _Products;
public void AddToProducts(Product product)
{
base.AddObject("Product", product);
}
You can also change the first constructor, if you’re interested.
After this you can use standard ways to query or update the Products table. You have to provide “entity frameworkish” connection string to make it work. The first option is to embed CSDL, MSL and SSDL files into resources and use res://<assemblyFullName>/<resourceName> specification in connection string (more info on http://msdn.microsoft.com/en-us/library/cc716756.aspx) or simply copy these three files into some folder and use path. My choice was the second (copying files into same folder as executable), so my code looks like (using MS SQL Express):
CustomClasses_EDMContext ctx = new CustomClasses_EDMContext("metadata=CustomClasses_EDM.csdl|CustomClasses_EDM.ssdl|CustomClasses_EDM.msl;provider=System.Data.SqlClient;provider connection string="Data Source=.\sqlexpress;Initial Catalog=test;Integrated Security=True"");
var q = from p in ctx.Products
where p.ID < 200
select p;
foreach (Product p in q)
{
Console.WriteLine(p.Name);
p.Name = p.Name + "R";
}
ctx.AddToProducts(new Product() { Name = "New Product", Price = 999 });
ctx.SaveChanges();
When you try to run this example, you’ll be able not even to enumerate items in table (products), but also to update, add etc. it.
It’s not as fast as using designer, you have to do some manual work (but I think you can write some tool to automate it and also EdmGen2 will help), however you’re using your custom objects (without rewriting these completely).
The work on POCO and persistence ignorance in version 2 of Entity Framework will be a step forward, no doubts, but this isn’t too bad isn’t it?
See also: How to use custom objects with associations in Entity Framework
Published on Databazovy Svet
Podobně jako minulý rok, i letos jsme se rozhodli uspořádat Firebird Developers’ Day. Loni místnost trochu přetékala, takže doporučuju registrovat včas.
Níže je oficiální program.
Konference Firebird Developers’ Day 2008 se uskuteční 16. října 2008 na pražské Přírodovědecké fakultě Univerzity Karlovy, Albertov 6, v sále označovaném jako Věž. K dispozici bude v den konání konference navigace.
Registrace začíná v 10.00 (začátek jsme posunuli, abychom vyšli vstříc mimopražským účastníkům) a vstup je zcela zdarma, podmínkou je pouze registrace. Budete-li mít jakékoli problémy s registračním formulářem, kontaktujte nás, prosím, na adrese fdd2008reg@dbsvet.cz.
Počet míst je omezen, proto doporučujeme v případě zájmu zaregistrovat se co nejdříve. Celý program je v českém jazyce. Každý účastník navíc obdrží hodnotnou databázovou publikaci z produkce společnosti Computer Press (ta o Firebirdu a InterBase od Pavla Císaře asi na všechny nevyjde, ale budou k dispozici stejně kvalitní).
Po vlastním programu bude následovat neformální setkání přednášejících a účastníků ve vhodném restauračním zařízení.
| 10:00 – 10:30 |
Registrace |
| 10:30 – 10:35 |
Zahájení a úvodní slova |
| 10:35 – 11:05 |
Co nového okolo Firebirdu?
Jiří Činčura, nezávislý IT specialista |
| 11:10 – 11:40 |
The Crash – krátké pojednání o jednom
přechodu z VMware na fyzické železo
Slavomír Skopalik, Elekt Labs |
| 11:45 – 12:35 |
Firebird a Python
Pavel Císař, IBPhoenix |
| 12:35 – 13:00 |
Přestávka |
| 13:00 – 13:30 |
11 let s “Ptákem Ohnivákem” – případová studie nasazení
databáze Firebird v ERP systémech firmy ABRA Software
Martin Shayna, ABRA Software |
| 13:35 – 14:25 |
Entity Framework a FirebirdClient
Jiří Činčura, nezávislý IT specialista |
| 14:30 – 15:00 |
OLAP – Jak postupovat při návrhu OLAP dotazů tak, aby byly
efektivní (krátký úvod do problematiky, úzká místa, sestavení dotazu)
Pavel Mazáč, Elekt Labs |
| 15:00 – 15:30 |
Přestávka |
| 15:30 – 16:20 |
Zálohování Firebird databází – desetkrát a pokaždé jinak
Ivan Přenosil, nezávislý IT specialista |
| 16:25 – 17:05 |
PostgreSQL v roce 2008
Pavel Stěhule, nezávislý IT specialista |
| 17:10 – 17:45 |
Panelová diskuse na téma Firebird a bezpečnost |
| 17:45 – 17:55 |
Losování cen, zakončení |
MS Sync Framework v1.0 is ready for download.