Kanithi's Professional Blog

January 26, 2010

ADO .NET Entity Model Drawbacks

Filed under: .NET — Veera Kanithi @ 4:16 pm

Following are the drawbacks/issues of ADO .NET Entity Framework (VS2008/3.5 SP1) which i encountered so far…

  • The Update Model Wizard overwrites the existing storage model when updating the EDM based on database changes. This means that any custom changes you made to the storage model will not be reflected in the updated model. So if you have any custom entities, make a backup of the existing EDM file before doing the update from database. For this same reason i always work on XML notation rather than in designer. This is very frustrating especially if you have huge model with all custom tables, views and Stored Procedures.
  • Entity model always enforces to use propertyref key, if you have not specified one, it throws an error “EntityType ‘… ‘ has no key defined”. So always you have to define ref key and the key column must not be a null value column, this is true even for Views as well.
  • Should be very careful in setting the ref keys, if they are not properly set the LINQ queries against the entity object may not work properly especially if queries have orderby clause. Make sure the ref keys have unique output especially when you are using Views and the designer creates some sort of default Ref Keys and they may not be unique.
  • If you are trying to modify the key column, entity model throws an error message “XXX is part of the object’s key information and cannot be modified.” This does makes sense but not in some situations especially if the key column consists of multiple columns and you want to update the value of one of the column eventually it wouldn’t. To overcome this remove the column that you would like to be on update  from object’s key.
  • I often get the error “The number of members in the conceptual type ‘XXX’ does not match with the number of members on the object side type ‘XXX’. Make sure the number of members are the same.” when i edit the entity model (edmx) file using xml editor. This means that the designer and xml are not in sync, after the edits in xml file just open the edmx in entity designer and move stuff around and save it. Error gone…
  • No support for Batch Updates, only one command per action. Also no support for DML statements using EntityCommand object

January 7, 2010

Custom web.config changes using generic SharePoint feature receiver

Filed under: MOSS 2007 — Veera Kanithi @ 10:29 pm

While I was looking for a general solution to edit Web.Config using a SharePoint feature, I found an excellent article from Ryan McIntyre about creating an external XML file with all the custom modifications and using a common feature receiver, it would take the changes from the external xml file and merge them in web.config using SPWebConfigModification object.

I am impressed with this approach, as this will eliminate frequent changes to the feature receiver class and avoid compilation and rebuilding WSP. Just change the XML file and re activate the feature, it’s that simple. Enough said, details including the feature receiver class is in his site below.

http://randomdust.com/blogs/ryan/archive/2008/03/22/featurereceiver-for-applying-custom-web-config-changes.aspx

But the code Ryan used for feature receiver class, works only for element modifications not for creating new sections. In my case I got to create a new section in the web.config file for example “connectionStrings”. After further exploring the code, he used EnsureChildNode modification type, this will be good only for modifications, if you want create new sections we must use EnsureSection. But EnsueSection has a disadvantage, we can’t remove the sections from web.config on de activating the feature. But I felt it is fine to leave an empty section in the web.config, it doesn’t harm. Following are my modifications (highlighted) to the feature receiver class that Ryan developed, to accommodate both sections and elements.

protected SPFeatureReceiverProperties _properties;

public override void FeatureActivated(SPFeatureReceiverProperties properties) {

string fileLoc = properties.Definition.RootDirectory + “\\WebConfigChanges.xml”;

//Check to see if a WebConfigChanges.xml file exists. If yes, we have work to do

if (System.IO.File.Exists(fileLoc))

{

//Grab the properties

_properties = properties;

this.ProcessChanges(fileLoc, false);

}

}

public override void FeatureDeactivating(SPFeatureReceiverProperties properties) {

string fileLoc = properties.Definition.RootDirectory + “\\WebConfigChanges.xml”;

//Check to see if a WebConfigChanges.xml file exists. If yes, we have work to do

if (System.IO.File.Exists(fileLoc))

{ //Grab the properties

_properties = properties;

this.ProcessChanges(fileLoc, true);

}

}

public override void FeatureInstalled(SPFeatureReceiverProperties properties) {

/* no op */

}

public override void FeatureUninstalling(SPFeatureReceiverProperties properties) {

/* no op */

}

private void ProcessChanges(string FileLocation, bool removeModification)

{

string xPathLocation;

string elementName;

string sectionName;

Dictionary<string, string> attributes = new Dictionary<string, string>();

using (XmlReader reader = XmlReader.Create(FileLocation))

{

//Loop through all of the changes

while(reader.ReadToFollowing(“WebConfigChange”))

{

//Clean out any attributes from past iterations

attributes.Clear();

xPathLocation = reader.GetAttribute(“XPathLocation”);

elementName = reader.GetAttribute(“ElementName”);

//Check if there is any new Section required

sectionName = reader.GetAttribute(“SectionName”);

elementName = reader.GetAttribute(“ElementName”);

//Make sure we have at least a path and element

if (xPathLocation == null || elementName == null || sectionName == null)

throw new Exception(“WebConfigChange missing required XPathLocation or ElementName or SectionName attributes”);

//Get the Attributes to apply

if (reader.ReadToDescendant(“Attribute”))

{

do

{

attributes.Add(reader.GetAttribute(“Name”), reader.GetAttribute(“Value”));

} while (reader.ReadToNextSibling(“Attribute”));

}

//Do the update

UpdateWebConfig(xPathLocation, elementName, sectionName, attributes, removeModification);

}

}

}

private void UpdateWebConfig(string XPathLocation, string ElementName, string SectionName,

Dictionary<string, string> Attributes, bool removeModification)

{

try

{

SPWebApplication webApp = null;

//Get the web app

//First check if it was deployed to a Site Collection

SPSiteCollection siteCol = _properties.Feature.Parent as SPSiteCollection;

if (siteCol == null)

{

//Check if it was deployed to a site

SPSite site = _properties.Feature.Parent as SPSite;

if (site == null)

{

//Check if it was deployed to a Site

SPWeb web = _properties.Feature.Parent as SPWeb;

if (web != null)

webApp = web.Site.WebApplication;

}

else

webApp = SPWebApplication.Lookup(new Uri(site.Url));

}

else

webApp = siteCol.WebApplication;

if (webApp != null)

{

SPWebConfigModification modification;

//If no section name

if (SectionName == null)

{

modification = new SPWebConfigModification(ElementName + CreateAttributeString(Attributes), XPathLocation);

modification.Owner = “Company.MOSS.FeatureReceiver”;

modification.Sequence = 0;

modification.Type = SPWebConfigModification.SPWebConfigModificationType.EnsureChildNode;

modification.Value = string.Format(CultureInfo.InvariantCulture, CreateModificationValueString(ElementName, Attributes), CreateModificationValueArgs(Attributes));

}

else

{

modification = new SPWebConfigModification(SectionName, XPathLocation);

modification.Owner = ” Company.MOSS.FeatureReceiver”;

modification.Sequence = 0;

modification.Type = SPWebConfigModification.SPWebConfigModificationType.EnsureSection;

modification.Value = String.Format(“<{0}/>”, SectionName);

}

 

if (removeModification)

webApp.WebConfigModifications.Remove(modification);

else

webApp.WebConfigModifications.Add(modification);

webApp.Farm.Services.GetValue<SPWebService>().ApplyWebConfigModifications();

}

else

throw new ApplicationException(“Could not locate a web application”);

}

catch (Exception ex)

{

System.Diagnostics.EventLog el = new System.Diagnostics.EventLog();

el.Source = “WebConfigFeature”;

el.WriteEntry(ex.Message);

}

}

/// <summary>

/// Accepts a dictionary object with all of the attributes for the web modification and

/// creates a string representing the attribute values which can be used when creating

/// the SPWebConfigModification object.

/// </summary>

/// <param name=”Attributes”></param>

/// <returns></returns>

private string CreateAttributeString(Dictionary<string, string> Attributes)

{

//Create a string that looks like this (no line breaks):

//[@Assembly=\”Company.Moss.Activities, Version=1.0.0.0, Culture=neutral, PublicKeyToken=9eed2245513232a4\”]

//[@Namespace=\”Company.Moss.Activities\”]

//[@TypeName=\”*\”][@Authorized=\”True\”]

string result = “”;

//Check if there are attributes

if (Attributes.Count > 0)

{

foreach (KeyValuePair<string, string> kvp in Attributes)

{

result += “[@” + kvp.Key + “=\”” + kvp.Value + “\”]”;

}

}

return result;

}

private string CreateModificationValueString(string ElementName, Dictionary<string, string> Attributes)

{

//Create a string that looks like this:

//”<authorizedType Assembly=\”{0}\” Namespace=\”{1}\” TypeName=\”{2}\” Authorized=\”{3}\”/>”

string result = “<” + ElementName;

//Check if there are attributes (Kind of silly if there aren’t!)

if (Attributes.Count > 0)

{

int i = 0;

foreach (string key in Attributes.Keys)

{

result += ” ” + key + “=\”{” + i.ToString() + “}\””;

i++;

}

}

result += ” />”;

return result;

}

private object[] CreateModificationValueArgs(Dictionary<string, string> Attributes)

{

//Create an object that looks like this:

//”Company.Moss.Activities, Version=1.0.0.0, Culture=neutral, PublicKeyToken=9eed2245513232a4″, “Company.Moss.Activities”, “*”, “True”

object[] result = new object[Attributes.Count];

int i = 0;

foreach(string value in Attributes.Values)

{

result[i] = value;

i++;

}

return result;

}

Here is the sample WebConfigChanges.xml file with connectionStrings section and other elements.

<?xml version=”1.0″ encoding=”utf-8″ ?>

<WebConfigChanges>

<WebConfigChange XPathLocation=”configuration” SectionName=”connectionStrings”>

</WebConfigChange>

<WebConfigChange XPathLocation=”configuration/connectionStrings” ElementName=”add”>

<Attributes>

<Attribute Name=”name” Value=”MOSSConnectionString” />

<Attribute Name=”connectionString” Value=”Data Source=XXX;Initial Catalog=XXX;User Id=XXX; Password=XXX” />

<Attribute Name=”providerName” Value=”System.Data.SqlClient” />

</Attributes>

</WebConfigChange>

<WebConfigChange XPathLocation=”configuration/system.web/httpHandlers” ElementName=”add”>

<Attributes>

<Attribute Name=”verb” Value=”*” />

<Attribute Name=”path” Value=”ChartImg.axd” />

<Attribute Name=”type” Value=”System.Web.UI.DataVisualization.Charting.ChartHttpHandler, System.Web.DataVisualization, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35″ />

</Attributes>

</WebConfigChange>

</WebConfigChanges>

Remember to place this file in the folder where elements.xml of the feature file is located under the 12 hive.

Blog at WordPress.com.