Match foreign key property with navigation property in Entity Framework metadata

by ondrejsv 31. August 2010 17:04

Entity Framework 4 brought a new way of dealing with references – directly through their foreign key value. While it takes off some abstraction, it’s more friendly to common situations in practice (e.g. selecting from drop down lists) and also it enables you to change a reference without having to load either the old referenced entities or the new one. Also note that this feature is optional; you won’t have your model polluted with foreign keys if you do not want.

This brings some new challenges in my scripts and old code dealing with EF metadata. Now I have to differentiate between “ordinary” simple properties and foreign key properties. Fortunately, it’s not that difficult.

You can get the matching foreign key property to a given navigation property by calling the GetDependentProperties() method which returns exactly entity properties which are dependent ones in the relationship. Note that we’re playing in the conceptual model area (which is what I want) and the foreign key column as implemented in the database could have different name. Also note that if there is a foreign key property, the method should return only value. If there isn’t (maybe you unchecked the “Include foreign key columns in the model” option in the Data Model Wizard), the collection will be empty.

And as usual some code for demonstration. It just outputs the list of all navigation properties in all entities and their corresponding foreign key property names:

var cx = new ModelContainer(); var mw = cx.MetadataWorkspace; var entities = mw.GetItems<EntityType>(DataSpace.CSpace); foreach (var en in entities) { Console.WriteLine(en.FullName); foreach (var np in en.NavigationProperties) { Console.WriteLine("- navigation property found: " + np.Name); if (np.ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.One || np.ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.One) { Console.WriteLine("-- is to one"); Console.WriteLine("--- its FK property is " + np.GetDependentProperties().ToList()[0].Name); } } }

Tags:

When BeginForm is not BeginForm<T>

by ondrejsv 30. August 2010 16:03

or why the ASP.NET MVC 2 client validation fails when you use Microsoft.Web.Mvc (aka MvcFutures)?

There’s an incredibly useful set of extension methods in the MvcFutures called BeginForm<T>. These methods provide an alternative type-safe way of building MVC forms instead of the old string based BeginForm. Instead of:

<% using (Html.BeginForm("Submit", "ThreadedInputController")) { %>

you just write

<% using (Html.BeginForm<ThreadedInputController>(c => c.Submit()) { %>

No strings here, everything type-safe.

But when you enable fantastic client side validations with the BeginForm<T> constructed form you end with a JavaScript error “Object Required” somewhere deep inside the MicrosoftMvcValidation.js:

image

on the line:

formElement[Sys.Mvc.FormContext._formValidationTag] = this;

The cause of this is that the new BeginForm<T> and the old BeginForm do not have a common implementation; in fact they are completely separated. The client side validation model requires all HTML forms have an ID value and also the framework expects this ID value to be set in the FormContext.FormId property of the current ViewContext. The original BeginForm does exactly this. If you don’t provide the form ID yourself, it will generate one in the form “formN” where N is the sequence number of the form.

It’s nothing difficult to fix the implementation but you must rename your extension methods to avoid conflict with the MvcFutures implementation or directly fix it in the MvcFutures and build your own version.

Here’s the fix (I renamed methods to the BeginFormA<T>):

private static readonly object _lastFormNumKey = new object(); private static int IncrementFormCount(IDictionary items) { object lastFormNum = items[_lastFormNumKey]; int newFormNum = (lastFormNum != null) ? ((int)lastFormNum) + 1 : 0; items[_lastFormNumKey] = newFormNum; return newFormNum; } [SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "This is an Extension Method which allows the user to provide a strongly-typed argument via Expression")] public static MvcForm BeginFormA<TController>(this HtmlHelper helper, Expression<Action<TController>> action, FormMethod method, IDictionary<string, object> htmlAttributes) where TController : Controller { TagBuilder tagBuilder = new TagBuilder("form"); if (helper.ViewContext.ClientValidationEnabled && htmlAttributes["id"] == null) { // forms must have an ID for client validation int formNum = IncrementFormCount(helper.ViewContext.HttpContext.Items); var formId = String.Format(CultureInfo.InvariantCulture, "form{0}", formNum); tagBuilder.GenerateId(formId); } tagBuilder.MergeAttributes(htmlAttributes); string formAction = Microsoft.Web.Mvc.LinkExtensions.BuildUrlFromExpression(helper, action); tagBuilder.MergeAttribute("action", formAction); tagBuilder.MergeAttribute("method", HtmlHelper.GetFormMethodString(method)); helper.ViewContext.Writer.Write(tagBuilder.ToString(TagRenderMode.StartTag)); var theForm = new MvcForm(helper.ViewContext); if (helper.ViewContext.ClientValidationEnabled) { helper.ViewContext.FormContext.FormId = tagBuilder.Attributes["id"]; } return theForm; }

You can download the whole static class with the extension methods.

Note: This bug is still not fixed in the ASP.NET MVC 3 Preview 1.

Tags: ,

Globalization is not an enemy 2 (N2CMS case)

by ondrejsv 28. August 2010 21:11

Some time ago I wrote an article about failures to properly write code concerning globalization, i.e. to write the code in such a way that it does not crash and works as intended when running in environments with regional settings you have not anticipated.

I’m playing with the wonderful N2CMS project these days. So far I’ve really enjoyed it. One of my first attempts to get known with it was to create a simple page with a date time field. They have an out-of-the-box date time control to render the field. As you can guess, I don’t have the en-US regional settings. Here’s the field:

image

One text box with a small nice calendar button for the date part and another text box sitting next for the time part. Let’s choose a date with the calendar.

image

It even recognizes the Slovak date pattern (DD. MM. YYYY):

image

So far so good. Let’s save the page and again open for edit. Bump:

image

Something very wrong happened. After some researching I found the DatePicker control’s source and there’s a quite ugly code :-):

if(value != null) { string[] dateTime = value.Split(' '); DatePickerBox.Text = dateTime[0]; if (dateTime.Length > 1) TimePickerBox.Text = dateTime[1].EndsWith(":00") ? dateTime[1].Substring(0, dateTime[1].Length - 3) : dateTime[1]; else TimePickerBox.Text = string.Empty; if (dateTime.Length > 2) TimePickerBox.Text += " " + dateTime[2]; // This could be AM/PM } else { DatePickerBox.Text = string.Empty; TimePickerBox.Text = string.Empty; }

I don’t know the reason behind that but parsing a datetime string on your own devices is a very bad idea.

And fix is simple. Just rely on the .NET Framework to do all the magic:

if(value != null)
{
    DateTime parsed;
    if (DateTime.TryParse(value, out parsed))
    {
        DatePickerBox.Text = parsed.ToShortDateString();
        if (parsed.Second == 0)
            TimePickerBox.Text = parsed.ToShortTimeString();
        else
            TimePickerBox.Text = parsed.ToLongTimeString();
    }
}
else
{
DatePickerBox.Text = string.Empty;
TimePickerBox.Text = string.Empty;
}

Disclaimer: My goal is not to whine about the N2CMS quality. No, I think that N2CMS is really a wonderful project and I’m a fan of it :-) Give it a try!

Tags:

It’s time to throw away greedy Firefox

by ondrejsv 28. August 2010 14:47

A quick quiz for today. What application that ate 1,3 GB of my memory and 50 % CPU I forcefully ended in the Task Manager to give me such a picture?:

image

Yes, Mozilla Firefox. What I dared to do? Download 3 files 300 MB each in size. Apparently Firefox Download Manager holds them in the memory until it downloads them and only then flushes them to disk! Complete fail. I had to switch to the Internet Explorer 8 to download them all (without any problem).

(Yes, I know about 3rd party download managers, I use one of them, but not for such small files.)

Tags:

VS2010 Bug: Entity Data Model Wizard disappears after selecting “Generate from Database”

by ondrejsv 6. June 2010 17:55

Today I found another annoying bug in Visual Studio 2010. I often work connected to my company LAN via VPN and I have generated some entity data models from databases over the wire in the past. Entity Data Model Wizard which runs when you add a new “ADO.NET Entity Data Model” item in Visual Studio has a “nice feature” that it remembers all connections you entered into it. Of course, if you disconnect from LAN, those connections are not available. If you are unlucky enough, one of those connections may be the first one and default in the combobox where you can select an existing connection to base your EDMX on. Visual Studio probably tries to get information on tables or whatever from the database but if the database is not reachable, it fails very silently and closes the window instead of letting you to select another connection or create a new one. #fail

Fortunately, these connections are the same you see in the Data Connections node of the Server Explorer. So delete all of those which are remote and you have no connection to them any more and the Data Model Wizard would behave properly.

Tags:

How to debug PHP applications on Windows

by ondrejsv 2. June 2010 00:20

If you need to dwelve into some PHP stuff and do not want to leave your comfortable Windows environment, just read on. It’s easy and no Apache will be harmed in this process.

Disclaimer: It’s been almost 10 years since I wrote the last serious line in PHP (PHP 3 then), so it’s possible that there is another way to debug PHP applications, or that I do not do things ideally or in the most elegant way but it did work for me.

You can install PHP conveniently and make it play nicely with IIS via the Microsoft Web Platform Installer. You then need some IDE to edit and debug the application. Microsoft Expression Web supports PHP but obviously not debugging. If you don’t mind spending some bucks, you can buy VS.Php or other similar product and use Visual Studio to do all PHP magic and stop reading. Or you may touch the other side of the world and download Eclipse with PHP Developer Tools (PDT) embedded. Unpack it but do not run yet. Download XDebug tool; note that you must download version that matches your PHP version and build flavor (if you don’t know, they have a fantastic tool that tells you what you want). Unpack it to any folder of your choice, open PHP.ini (by default in C:\Program Files\PHP) and at the very end of the file paste these lines:

[xdebug] xdebug.remote_enable=1 xdebug.remote_host="localhost" xdebug.remote_port=9000 xdebug.remote_handler="dbgp" zend_extension = C:\Program Files\php\plugins\php_xdebug-2.1.0RC1-5.2-vc6-nts.dll

Of course, the path in the last line should reflect the folder you unpacked XDebug zip into. Also note that if you have some non-standard build of PHP (on Windows it means something else than non-debug non-thread-safe), you may need to change the last line – read full instructions.

Verify that XDebug is correctly installed by running php.exe –m. The last line should read:

[Zend Modules] Xdebug

Restart IIS (iisreset) and now you may fire Eclipse. Go to Windows/Preferences/PHP/Debugger and change it from default Zend Debugger to XDebug.

Create a new file, type in some PHP code, set a breakpoint (Ctrl+Shit+B? What the…? I must find a way to change its key bindings to Visual Studio ones) and run. Yes, it works :-) :

image

Tags:

WebClientFactoryPackage2 not found when upgrading from WCSF 2.0 to WCSF 2010

by ondrejsv 26. May 2010 20:39

patterns & practices team has released final version of their Web Client Software Factory. After you have migrated your solution to Visual Studio 2010, you may encounter this message:

image

Framework manifest contains location for package WebClientFactoryPackage2 configuration file, but the file was not found. Do you want to permanently remove the package from the current solution?

If you want to definitely convert to Visual Studio 2010, you may safely answer Yes. This error is caused by references in the solution.gpState file to the old version of the software factory. After removing you must reenable the WCSF in the Tools –> Guidance Package Manager –> Enable/Disable Packages in Visual Studio. Then references to the WCSF 2010 will be created (WebClientGuidancePackage2010).

Tags:

Silverlight DataForm’s autogenerated fields send empty strings to database

by ondrejsv 28. March 2010 17:18

Silverlight Toolkit comes with a great control for quick building typical business application screens – DataForm, a sibling control to the DataGrid for showing and editing a single record. If you use its field autogeneration feature, you may be surprised when looking to the database after its first submit. All your ((n)var)char columns rendered as TextBoxes in the DataForm that had been empty have also empty string values in the database:

image

This is not what you usually want. If the field is left blank, I expect the database field be NULL instead of an empty string. So what to do to persuade the DataForm to send nulls in this case?

An IValueConverter, of course! First we define a suitable one which returns null when converting back an empty string:

public class SourceNullValueConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { return value == null ? "" : value.ToString(); } public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { if (targetType != typeof(string)) return value; if (value == null) return null; return value.ToString() == "" ? null : value.ToString(); } }

Secondly, we need to force the DataForm to use this value converter instead of its own default DataFormToStringConverter. We do this by handling AutoGeneratingField event where we get the already built binding, copy it (by using CreateCopy extension method from the Silverlight Business Application template) and set our new value converter:

private void EmployeeForm_AutoGeneratingField(object sender, DataFormAutoGeneratingFieldEventArgs e) { if (e.Field.Content.GetType() == typeof(TextBox)) { Binding binding = e.Field.Content.GetBindingExpression(TextBox.TextProperty).ParentBinding.CreateCopy(); binding.Converter = new SourceNullValueConverter(); e.Field.Content.SetBinding(TextBox.TextProperty, binding); } }
image 

Case closed, Poirot!

kick it on DotNetKicks.com

Tags: ,

Easily migrate MySQL database into SQL Server

by ondrejsv 27. March 2010 20:11

If you want to migrate for whatever reason your MySQL database to SQL Server, forget all commercial tools or pesky DTS or SSIS packages! There’s a gem on the Microsoft SQL Server site called in the sterile marketing language Microsoft SQL Server Migration Assistant for MySQL or better SSMA for MySQL (currently CTP). Grab it from the Migration page.

image

Migration process has two steps – first you convert MySQL schema into corresponding SQL Server structures. You can either create tables directly on SQL Server instance or save the schema into file and run it later. In the second step you copy data. Everything in two clicks!

You can change some options regarding conversion between types and other and also you have choice to select just objects you are interested to migrate.

Two clicks and voila:

image

There are similar tools for migrating from Oracle, Sybase and Access on the Microsoft web site. Hopefully they give us a PostgreSQL one, too.

kick it on DotNetKicks.com

Tags: ,

How to: Create computed/custom properties for sample data in Blend/Sketchflow

by ondrejsv 14. March 2010 20:32

I blogged about sample data in Microsoft Blend/SketchFlow previously. SketchFlow is a great tool for rapidly building interactive screen prototypes. Sample data feature helps you to create plausible screen mocks quickly. I want to emphasize words interactive prototypes. Yes, user can click here and there and sees the entire “application flow”. Previously we mocked screens in HTML, had them rendered and sent this to our customers as a package full of JPEGs. Almost as a rule we had small disputes with customers who were arguing that they just cannot “grasp the application” from JPEGs. Now we can just publish a Silverlight prototype to our server and customers browse it throughout.

Hopefully I don’t need to note that logically connected screens should play together. Having double clicked a record in a datagrid on one screen and being redirected to another screen showing detailed information on this only record, data in fields should be the same (or related) to the record I clicked on the first screen. If you use sample data, it means that you should bind the first and second screen against the very same data source.

One problem I encountered is managing data derived from other fields in sample collection. Let’s say I have a customers collection with usual data like first name, last name and birth date. The first screen shows this list but I want to have only one column for customer name showing first and last name concatenated. I need them separated in my collection because the second “customer detail” screen would show them in separate text boxes. I could create a new string field and manually type in the full name but I am lazy to do such work and frankly have personal objections to do so. I prefer the way the full name field just computes itself. That way I can modify either name and full name updates automatically.

image

Double clicking on the Natasha row would bring me to the second screen with separate fields:

image

Fortunately, this task is not difficult. Your sample data collections are stored as XML files inside the SampleData folder in the XXXScreens project. For each such XML file, Blend generates a corresponding C# file with two ordinary class, one representing the collection and one the collection item (named Item):

image

public class Employees : System.ComponentModel.INotifyPropertyChanged { public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged; protected virtual void OnPropertyChanged(string propertyName) { if (this.PropertyChanged != null) { this.PropertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName)); } } public Employees() { try { System.Uri resourceUri = new System.Uri("/SilverlightPrototype_Derived.Screens;component/SampleData/Employees/Employees.xaml", System.UriKind.Relative); if (System.Windows.Application.GetResourceStream(resourceUri) != null) { System.Windows.Application.LoadComponent(this, resourceUri); } } catch (System.Exception) { } } private ItemCollection _Collection = new ItemCollection(); public ItemCollection Collection { get { return this._Collection; } } } public class Item : System.ComponentModel.INotifyPropertyChanged { public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged; protected virtual void OnPropertyChanged(string propertyName) { if (this.PropertyChanged != null) { this.PropertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName)); } } private string _LastName = string.Empty; public string LastName { get { return this._LastName; } set { if (this._LastName != value) { this._LastName = value; this.OnPropertyChanged("LastName"); } } } private string _FirstName = string.Empty; public string FirstName { get { return this._FirstName; } set { if (this._FirstName != value) { this._FirstName = value; this.OnPropertyChanged("FirstName"); } } } }

Pretty boring code. If only the Item class would be generated with the partial directive, we could add our own class with the FullName computed property.

Let’s start some hacking then. Close Blend, start your favorite text editor and open the file C:\Program Files\Microsoft Expression\Blend 3\Templates\en\SampleDataCode.cs. This is the template Blend uses for generating C# code from the sample data XML source file.

Change line 43 from:

public class COMPOSITE_TYPE : System.ComponentModel.INotifyPropertyChanged //CompositeTypeHeader - BEGIN

to:

public partial class COMPOSITE_TYPE : System.ComponentModel.INotifyPropertyChanged //CompositeTypeHeader - BEGIN

Now start Blend again, open your project, force Blend to regenerate the code file (by adding a new property and removing it immediately). If you open the sample data code file, you can notice that the Item class now has the partial keyword!

Add a new class, change the namespace to exactly math the one in the original code file and write your own partial class, like mine:

namespace Expression.Blend.SampleData.Employees { public partial class Item { public string FullName { get { return string.Format("{0} {1}", FirstName, LastName); } } } }

Job done! I may create a new bound column to my datagrid:

<data:DataGridTextColumn Header="Full Name" Binding="{Binding FullName}"/>

Note: Blend may not recognize your new properties, so you may need to write your bound fields in XAML yourself, not in the Blend UI.

kick it on DotNetKicks.com

Tags: ,