Posts Tagged Visual Studio

Complex types and stored procedures – 2nd edition

Some time ago I was writing about not supported scenario when you have entity with complex type and you want to map result of stored procedure to this entity. I couldn’t believe that this, from my point of view fairly common, scenario will not be supported in designer in RTM.

Right now I’m running RC of Visual Studio 2010 (the development probably in feature freeze mode) and the limitation is still there. :( Jeff Derstadt was not lying. Although Zeeshan Hirani in forum said, he was able to do it manually, it’s uncomfortable. Same as complex types in EFv1.

Looks like complex types, sadly, are still not first class citizens for designer.

Tags: ,

Complex types and stored procedures

I like the idea of complex type. Sadly the designer didn’t supported complex types in EFv1/VS2008, although you could use it manually editing the model (it’s just a XML file). The designer in EFv2/VS2010 supports complex types (and you can use it also with EFv1, see this) hence it’s time to start really using these.

Unfortunately nothing is perfect. As far as you don’t wanna map some stored procedure result to collection of entities, then the designer will tell you, that it’s not supported. :( And Jeff Derstadt pointed in forum that this limitation will not be solved in RTM.

I’m using EFv4 in my current project and thanks to ability to map functions directly to LINQ functions via EdmFunction attribute I was able to to a lot of work via functions and queries created by EF itself. But I always feel a little bug in my head saying “What if you’ll need it later?”. Sure I can redo all back into direct properties, but if it’s close to the end of the project it’s pretty expensive to do it.

What a pity, I see complex types as a good concept, but I’m too careful to close myself the path with SPs.

Tags: ,

Quick Search renamed to Navigate To

In March I wrote about one of the new features in Visual Studio, time being called Quick Search. If you look into VS2010 Beta 2 (current latest) you may be confused as there’s no function called like that. Now it’s called Navigate To. Luckily the shortcut is untouched – Ctrl+,. So if you wanna give it a try, look for this new name (or use the good old shortcut).

Tags:

Entity Framework 4 – MS Fest 2009

Nová verze Entity Frameworku už pomalu klepe na dveře a proto není od věci podívat se, co nového nabídne. V rámci přednášky na MS Festu projdu největší změny a vylepšení. Rozhodně je na co se těšit – pokud již EF používáte, tak na ulehčení života a pokud ještě ne, tak na ještě větší lákadla jej použít. A vzhledem k plánované večerní akci bude prostor i pro kuloární diskuze, nejen o EF.

Tags: , , , , , , ,

VMWare Workstation 7 and Visual Studio 2010 rendering problem

I recently migrated from VPC to VMWare Workstation. So far all looks good only one problem I faced two days ago. When I run Visual Studio 2010 (Beta 2), the menu rendering was odd, text in code editor was disappearing and so on. After some searching I found, that it may be caused by 3D graphics acceleration turned on in VMWare Workstation. Surprisingly you have to turn it off – either in system, setting DisableHWAcceleration in registry (it’s for WPF) or unchecking the 3D acceleration in VM’s settings. After this adjustment (my choice was the VM level, as it may be improved later and it’s IMO easier to turn it on), all works great. I hope when the RTM of Visual Studio 2010 will be released, this will work as expected.

Tags: ,

First touches on Code Only in EF4

I finally got my hands on the new feature in EF4, Code Only. It’s now available in feature CTP. What’s the code only? Very shortly you write just a code and express your mapping in code as well. There’s no model, no edmx file, no CSDL, MSL, SSDL files.

The current version is pretty limited, it’s more preview than something you can do some work with (which I wasn’t aware of and I was little disappointed). You can read more about what will be available on http://blogs.msdn.com/efdesign/archive/2009/06/10/code-only.aspx, http://blogs.msdn.com/efdesign/archive/2009/08/03/code-only-enhancements.aspx and http://thedatafarm.com/blog/data-access/next-version-of-ef-code-only-design-laid-out-by-ms/.

I mainly wanted to try it on a non standard (read: not “follow this demo”) MS SQL database and on Firebird as well. The first bad news is, that current CTP supports only SqlClient. And probably some following previews will too, as the other providers model will be built on top of it (but I’ll try to push this as much as I can, to see some Firebird demo soon). The other is, that the currently available version is limited, even features in first Code Only blog post are not working. :( Right now you can only create a context and use it for work with all defaults – default names for tables, default mapping etc.

using (SqlConnection conn = new SqlConnection(@"Data Source=.\sqlexpress;Initial Catalog=testovaci;Integrated Security=True;Pooling=False"))
{
	ContextBuilder<COContext> builder = new ContextBuilder<COContext>();
	COContext context = builder.Create(conn);
	string script = context.CreateDatabaseScript();
	context.Masters.ToArray();
}

Nothing special. If you try it with FirebirdClient, you’ll get NotSupportedException immediately. Dammit.

using (FbConnection conn = new FbConnection("database=localhost:rrr.fdb;user=sysdba;password=sysdba"))
{
	ContextBuilder<COContext> builder = new ContextBuilder<COContext>();
	builder.Create(conn);
}

Despite the frustration I found couple of new interesting extension methods (in Microsoft.Data.Objects, also ContextBuilder sits there). One of these is CreateDatabaseScript. This method works not only with Code Only created ObjectContext, but on every ObjectContext. So you can create your database creation script during runtime even if you’re using i.e. EDMX file easily. I’m also seeing great opportunity for this with Code Only setup during runtime. You can have different builds with different setups and create script for users based on selection. And by the way, there’s also CreateDatabase method available. But again right now works only with MS SQL only. But I know other databases will be supported as well, I have tested some pieces already.

I like the Code Only feature, maybe more than Model First (probably because I’m using ERD tools to model my databases). And I’m looking forward to see more progress on it, and also the model for 3rd party providers.

Tags: , , ,

Tab closing button in Visual Studio 2010

The new Visual Studio 2010 looks. I’m more interested in .NET FW 4.0 and C# 4 new features, but some of the new stuff makes me happy to. But one new function makes me crazy. The editor tabs has now the closing button on each tab. Similar to what browsers have. But I’m used to look at it in upper right corner. And every time I’m about to close a file using a mouse, I’m starting to move wrong way. I hope to get used to this new feature or have some option to turn on the old behavior.

Tags:

FirebirdClient 2.5 Final released

I’m happy to announce, after about 47 000 000 seconds of thinking and development, release of FirebirdClient 2.5. This new shiny release contains couple of very interesting new features:

  • Implementation of Firebird 2.1 protocol improvements. These improvements are focused on making the communication more efficient on slow and with high latencies networks like the internet.
  • Entity Framework support. Entity Framework is new, rich OR mapping and modeling tool, sitting on the top of ADO.NET. It is store agnostic, using ADO.NET provider to work smoothly, and the FirebirdClient has now build-in support for it.
  • Windows integrated auth. Firebird server is now able on Windows to authenticate users using a system (ActiveDirectory, etc.), and when you omit username and password FirebirdClient will try to negotiate with server this kind of authentication.
  • Timeout for wait transactions.

Of course, this release contains also lot of bug fixes and performance improvements. You can see the most important on http://tracker.firebirdsql.org/sr/jira.issueviews:searchrequest-printable/temp/SearchRequest.html?&pid=10003&fixfor=10170&fixfor=10340&fixfor=10261&fixfor=10240&fixfor=10230&status=5&status=6&sorter/field=issuekey&sorter/order=DESC&tempMax=1000. I’m also happy to say, that we have again full set of builds available for download. You can download build for .NET 3.5 (and unit tests), .NET 2.0, Compact Framework, Mono (Linux build) and also ASP.NET web providers.

One of the early adopters, SMS-Timing, of Entity Framework support for Firebird comments:
“Thanks to Jiri’s (link) work the Firebird .NET Data Provider made a lot of progress and is now even supporting the Entity Framework. Because of the adaptations we were able to use the newest .NET technologies in a modern programming environment together with a well known Firebird Database. In our industry (entertainment) the customers expect new and exciting software, and therefore the development tools need to be cutting edge. These developments in Firebird have a big impact on our products, and we hope that it brings the same boost to the Firebird Community itself. A preview of our newest software: www.fast4thefuture.com, http://www.sms-timing.com/en/software_kiosk.php.”

You can download the new version on http://www.firebirdsql.org/index.php?op=files&id=netprovider.

Tags: , , , , ,

FirebirdClient 2.5.0 Beta 2

I’m glad to announce Beta 2 release of FirebirdClient 2.5.0.

This release contains implementation of new Firebird 2.1 protocol,
couple of bugfixes in Entity Framework support and other bug fixes and
improvements.

Thanks SMS-Timing for support on new protocol and Entity Framework support and Vlad Khorsun for answering all my questions on new protocol.

Download on http://www.firebirdsql.org/index.php?op=files&id=netprovider.

For more information about this release visit:
http://tracker.firebirdsql.org/secure/ReleaseNote.jspa?version=10340&styleName=Text&projectId=10003
for detailed changes follow the SVN log or visit:
http://tracker.firebirdsql.org/browse/DNET?report=com.atlassian.jira.plugin.ext.subversion:subversion-project-tab

Tags: , , , , ,

Quick Search and Call Hierarchy in VS 2010

I’m not kind of guy hungry for thousands of new features in my current development IDE. In fact I’m happy for decently smart editor, because my work mainly involves BL etc. But couple of new features in new Visual Studio 2010 I really like.

One is called Quick Search. It simply allows you to find a lot of stuff from simple window – files in solution, methods etc. And it’s smart too. If you have file named, let’s say MyCoolClass.cs, you can type just MCC and the file will be found too. Nice, isn’t it? Almost as fast as navigating in text in VI editor. ;)

And other is called Call Hierarchy. It’s simple tree showing you who is calling selected methods and vice versa. You can easily traverse through this tree and see paths where your code is going. And you can of course navigate to methods selected in the window.

Simple functions, but may help a lot. What is your favourite in upcoming VS or current VS maybe with some plugin?

Tags:

Mapping stored procedures that are returning non-entity result in EDM

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.

Tags: , , ,

Firebird ADO.NET Data Provider 2.5.0 Beta 1 for .NET 3.5/2.0 [with Entity Framework support]

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.

Tags: , , , , , , ,

Making names of entities (or any identifiers) in Entity Framework model "code and developer friendly" (= not uppercase)

Some databases behave according to standard so without quoting (which is a good way to hell), you got all in uppercase in your new shinny model generated from database (and yes, you should start modeling in empty model and define mapping later – just not to be screwed with relational world). Anyway a lot of people, including me, is generating model from database and then changing it.

But spending first hour or so of your work with renaming entities (or properties …) isn’t much fun. With same experience came guys from SMS-Timing, because they’re testing Entity Framework support for Firebird right now (and Firebird is behaving according to standard in this). Hence I’ve got the idea to make these identifiers little bit more code and developer friendly.

Because the *.EDMX file is just a couple of XML files together (CSDL, MSL, SSDL and designer stuff) you can tweak it by hand or by simple program. To get rid of all in uppercase I’ve created simple code (or program if you compile it yourself). It’s a simple program transforming names of entities to titlecase and also removing underscores with capitalizing next character.

static void Main(string[] args)
{
    if (args.Length != 2)
        return;

    if (!File.Exists(args[0]))
        return;
    if (File.Exists(args[1]))
        return;

    XDocument xdoc = XDocument.Load(args[0]);

    const string CSDLNamespace = "http://schemas.microsoft.com/ado/2006/04/edm";
    const string MSLNamespace = "urn:schemas-microsoft-com:windows:storage:mapping:CS";
    const string DiagramNamespace = "http://schemas.microsoft.com/ado/2007/06/edmx";
    XElement csdl = xdoc.Descendants(XName.Get("Schema", CSDLNamespace)).First();
    XElement msl = xdoc.Descendants(XName.Get("Mapping", MSLNamespace)).First();
    XElement designerDiagram = xdoc.Descendants(XName.Get("Diagram", DiagramNamespace)).First();

    Func<string, string> transformation = (string input) =>
        {
            Regex re = new Regex(@"(\w+)(\W*?)$", RegexOptions.None);
            return re.Replace(input, new MatchEvaluator(
                (Match m) =>
                {
                    string replace = m.Groups[1].Value;

                    StringBuilder result = new StringBuilder(m.Length);
                    for (int i = 0; i < replace.Length; i++)
                    {
                        if ((i == 0) ||
                            (i > 0 && replace[i - 1] == '_'))
                        {
                            result.Append(char.ToUpper(replace[i]));
                        }
                        else if (replace[i] == '_')
                        {
                            continue;
                        }
                        else
                        {
                            result.Append(char.ToLower(replace[i]));
                        }
                    }
                    result.Append(m.Groups[2].Value);

                    return result.ToString();
                }));
        };

    #region CSDL
    foreach (var entitySet in csdl.Element(XName.Get("EntityContainer", CSDLNamespace)).Elements(XName.Get("EntitySet", CSDLNamespace)))
    {
        entitySet.Attribute("Name").Value = transformation(entitySet.Attribute("Name").Value);
        entitySet.Attribute("EntityType").Value = transformation(entitySet.Attribute("EntityType").Value);
    }
    foreach (var associationSet in csdl.Element(XName.Get("EntityContainer", CSDLNamespace)).Elements(XName.Get("AssociationSet", CSDLNamespace)))
    {
        foreach (var end in associationSet.Elements(XName.Get("End", CSDLNamespace)))
        {
            end.Attribute("EntitySet").Value = transformation(end.Attribute("EntitySet").Value);
        }
    }

    foreach (var entityType in csdl.Elements(XName.Get("EntityType", CSDLNamespace)))
    {
        entityType.Attribute("Name").Value = transformation(entityType.Attribute("Name").Value);
    }
    foreach (var association in csdl.Elements(XName.Get("Association", CSDLNamespace)))
    {
        foreach (var end in association.Elements(XName.Get("End", CSDLNamespace)))
        {
            end.Attribute("Type").Value = transformation(end.Attribute("Type").Value);
        }
    }
    #endregion

    #region MSL
    foreach (var entitySetMapping in msl.Element(XName.Get("EntityContainerMapping", MSLNamespace)).Elements(XName.Get("EntitySetMapping", MSLNamespace)))
    {
        entitySetMapping.Attribute("Name").Value = transformation(entitySetMapping.Attribute("Name").Value);
        foreach (var entityTypeMapping in entitySetMapping.Elements(XName.Get("EntityTypeMapping", MSLNamespace)))
        {
            entityTypeMapping.Attribute("TypeName").Value = transformation(entityTypeMapping.Attribute("TypeName").Value);
        }
    }
    #endregion

    #region Designer
    foreach (var item in designerDiagram.Elements(XName.Get("EntityTypeShape", DiagramNamespace)))
    {
        item.Attribute("EntityType").Value = transformation(item.Attribute("EntityType").Value);
    }
    #endregion

    using (XmlTextWriter writer = new XmlTextWriter(args[1], Encoding.Default))
    {
        xdoc.WriteTo(writer);
    }
}

The code is pretty simple. It just goes to thru the file and changes what needs to be changed. Mainly CSDL and MSL parts. Changes in designer part are not necessary, but you’ll lose positions etc. when you don’t do it. This is kind of this-afternoon-code – maybe I forgot something, maybe the RE is matching too much… Feel free to report problems in comments.

If you want to change also names of properties you can either tweak the code yourself or ask in comments, if I found some time, I’ll extend it. And of course, if you have some special naming convention in your company (i.e. every table has T_ prefix), just change the transformation function.

Tags: , , ,

Update Model from Database and CatalogName

Entity Framework support for Firebird had a problem, when you created model and then tried to update model (Update Model from Database) VS freeze. I was pretty sure, that’s a problem of server – because I was using 2.5 build from HEAD that cannot be considered as stable and the 2.1 was working fine (except the left outer join problem ;) ) (because foreign keys/associations were not generated the problem wasn’t fired). And I was wrong.

Similar to problem I described on http://forums.microsoft.com/MSDN/ShowPost.aspx?siteid=1&PostID=3519267, the problem was in NULL in CatalogName in DefiningQuery in SSDL for store. Funny is that generating model from EdmGen and also in wizard was working fine, only updating was failing. But no exception, no error, nothing. Just freeze. If I had NULL in SchemaName I was getting exception in EdmGen leastways.

OK, now – just to be safe – CatalogName and also SchemaName isn’t NULL, but dummy string. No attempts to be smart. ;)

Never mind, could be worse. Now it’s fixed, so you can grab build from http://netprovider.cincura.net/ and test it. Eh, and if you’re looking for some FB with fixed left outer join, check i.e. http://cid-bdb67deba4c656e5.skydrive.live.com/self.aspx/Ve%c5%99ejn%c3%a9/FB%7C_FixedLeftOuterJoin/Firebird-2.5.0.21381-0%7C_Win32.zip, it’s a snapshot of current 2.5 trunk.

This problem itself has been also discussed in comments here.

Tags: , ,

DDEX for Firebird and Visual Studio 2010

What’s better than finding what you need to fix for upcoming release of product? :-) I get finally Visual Studio 2010 CTP up and running and decided to test whether DDEX provider for Firebird is working fine with it (else I need to find why not and fix these issues). Luckily it’s working fine. I’ve changed reg files appropriately for VS2010 and modified machine.config for .NET FW 4.0. No problem, 10 minutes and it was done.

Check this out. Nice, isn’t it? :-)

Tags: ,

Nové .NET logo

Při všem shonu okolo PDC a Windows 7, Azure aspol. jsem úplně minul ohlášení o novém logu pro .NET. Posuďte sami.

Není ošklivé, ale ani mě neposadilo na zadek. Takový dobrý standard dobrého grafika. Co myslíte?

Tags: , ,

Videa z PDC2008

Videa z PDC2008 jsou dostupná zdarma na Channel9. Není potřeba registrace.

Tags: , ,

.NET Framework 4 Poster

Ačkoli .NET Framework 4 tu ještě není, můžete mrknout na plakát. Více na http://blogs.msdn.com/brada/archive/2008/10/29/net-framework-4-poster.aspx.

PDF verze | DeepZoom verze

Tags: , ,

How to use custom objects with associations in Entity Framework

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

Tags: , , , ,

How to map your custom objects in Entity Framework

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

Tags: , , , ,