Ways to update only modified columns in table using LINQ - linq-to-sql

I have 20 fields on form, how to update fields modified by user during runtime and how to check which fields have changed so that i can only update those values in table using LINQ. I am working on windows application using C# and VS2010
Please refer the code (Currently i am passing all values, i knw this is not the correct way)
private void UpdateRecord(string groupBoxname)
{
using (SNTdbEntities1 context = new SNTdbEntities1())
{
{
Vendor_Account va = new Vendor_Account();
var Result = from grd in context.Vendor_Account
where grd.Bill_No == dd_billNo.Text
select grd;
if (Result.Count() > 0)
if ((dd_EditProjectName.Text!= "Select") && (dd_billNo.Text!="Select") && (dd_editVendorName.Text!="Select"))
{
foreach (var item in Result)
{
va.Account_ID = item.Account_ID;
}
va.Amount_After_Retention = Convert.ToDecimal(txt_AD_AfterRet.Text);
va.Balance = Convert.ToDecimal(txt_AD_Balance.Text);
va.Bill_Amount = Convert.ToDecimal(txt_AD_BillAmount.Text);
va.Bill_Date = Convert.ToDateTime(dt_AD_BillDate.Text);
va.Bill_No = dd_billNo.Text;
va.Comments = txt_AD_Comments.Text;
va.Paid_Till_Date = string.IsNullOrEmpty(txt_AD_Paid.Text)?0:Convert.ToDecimal(txt_AD_Paid.Text);
va.Project_Name = dd_EditProjectName.Text;
va.Retention_Perc = Convert.ToDecimal(txt_retPerc.Text);
va.Amount_After_Retention = Convert.ToDecimal(txt_AD_AfterRet.Text);
va.Vendor_Name = dd_editVendorName.Text;
va.Vendor_Code = txt_AD_Code.Text;
context.Vendor_Account.ApplyCurrentValues(va);
//context.Vendor_PersonalInfo.AddObject(vpi);
context.SaveChanges();
MessageBox.Show("Information Updated Sucessfully!");
lbl_Warning.Text = "";
entityDataSource1.Refresh();
}
else
{
MessageBox.Show("Vendor Name,Project Name and Bill No cannot be blank!!");
}
}
}
}

Entity framework will do that task.
Since you didn't provide any code, I cannot be precise about the answer but please check those links:
http://msdn.microsoft.com/en-us/library/aa697427(v=vs.80).aspx, section:Manipulating Data and Persisting Changes
http://www.codeproject.com/KB/database/sample_entity_framework.aspx
Note that the SaveChanges() function will update any modification done the records in EF.

Create some field dublicates, and compare value from the form element with the local dublicate, if it was changed than update it.

Related

Get Row Count for Data Transferred using EzAPI SSIS

I am transferring some data from one table to another using SSIS with EzAPI. How can I get the number of rows that were transferred?
My setup is as follows
EzPackage package = new EzPackage();
EzOleDbConnectionManager srcConn;
EzOleDbSource src;
EzOleDbConnectionManager destConn;
EzOleDbDestination dest;
EzDataFlow dataFlow;
destConn = new EzOleDbConnectionManager(package); //set connection string
srcConn = new EzOleDbConnectionManager(package);
dataFlow = new EzDataFlow(package);
src = Activator.CreateInstance(typeof(EzOleDbSource), new object[] { dataFlow }) as EzOleDbSource;
src.Connection = srcConn;
src.SqlCommand = odbcImport.Query;
dest = Activator.CreateInstance(typeof(EzOleDbDestination), new object[] { dataFlow }) as EzOleDbDestination;
dest.Connection = destConn;
dest.AttachTo(src, 0, 0);
dest.AccessMode = AccessMode.AM_OPENROWSET_FASTLOAD;
DTSExecResult result = package.Execute();
Where in this can I add something to get the number of rows? For all versions of SQL server 2008r2 and up
The quick answer is that the Row Count Transformation isn't included out of the box. I had a brief post about that: Row Count with EzAPI
I downloaded the source project from CodePlex and then edited EzComponents.cs (in EzAPI\src) and added the following code
[CompID("{150E6007-7C6A-4CC3-8FF3-FC73783A972E}")]
public class EzRowCountTransform : EzComponent
{
public EzRowCountTransform(EzDataFlow dataFlow) : base(dataFlow) { }
public EzRowCountTransform(EzDataFlow parent, IDTSComponentMetaData100 meta) : base(parent, meta) { }
public string VariableName
{
get { return (string)Meta.CustomPropertyCollection["VariableName"].Value; }
set { Comp.SetComponentProperty("VariableName", value); }
}
}
The component id above is only for 2008.
For 2012, it's going to be E26997D8C-70DA-42B2-8208-A19CE3A9FE41 I don't have a 2012 installation at the moment to confirm I didn't transpose a value there but drop a Row Count component onto a data flow, right click and look at the properties. The component/class id is what that value needs to be. Similar story if you're dealing with 2005.
So, once you have the ability to use EzRowCountTransform, you can simply patch it into your existing script.
// Create an instance of our transform
EzRowCountTransform newRC = null;
// Create a variable to use it
Variable newRCVariable = null;
newRCVariable = package.Variables.Add("RowCountNew", false, "User", 0);
// ...
src.SqlCommand = odbcImport.Query;
// New code here too
newRC = new EzRowCountTransform(dataFlow);
newRC.AttachTo(src);
newRC.Name = "RC New Rows";
newRC.VariableName = newRCVariable.QualifiedName;
// Continue old code
I have a presentation on various approaches I've used over time and what I like/don't like about them. Type more, click less: a programmatic approach to building SSIS. It contains sample code for creating the EzRowCountTransform and usage.

Warning messages with EZAPI EzDerivedColumn and input columns

When adding a derived column to a data flow with ezAPI, I get the following warnings
"Add stuff here.Inputs[Derived Column Input].Columns[ad_zip]" on "Add
stuff here" has usage type READONLY, but is not referenced by an
expression. Remove the column from the list of available input
columns, or reference it in an expression.
I've tried to delete the input columns, but either the method is not working or I'm doing it wrong:
foreach (Microsoft.SqlServer.Dts.Pipeline.Wrapper.IDTSInputColumn100 col in derFull.Meta.InputCollection[0].InputColumnCollection)
{
Console.WriteLine(col.Name);
derFull.DeleteInputColumn(col.Name);
}
I have the following piece of code that fixes the problem.
I got it from a guy called Daniel Otykier. So he is propably the one that should be credited for it... Unlesss he got it from someone else :-)
static public void RemoveUnusedInputColumns(this EzDerivedColumn component)
{
var usedLineageIds = new HashSet<int>();
// Parse all expressions used in new output columns, to determine which input lineage ID's are being used:
foreach (IDTSOutputColumn100 column in component.GetOutputColumns())
{
AddLineageIdsFromExpression(column.CustomPropertyCollection, usedLineageIds);
}
// Parse all expressions in replaced input columns, to determine which input lineage ID's are being used:
foreach (IDTSInputColumn100 column in component.GetInputColumns())
{
AddLineageIdsFromExpression(column.CustomPropertyCollection, usedLineageIds);
}
var inputColumns = component.GetInputColumns();
// Remove all input columns not used in any expressions:
for (var i = inputColumns.Count - 1; i >= 0; i--)
{
if (!usedLineageIds.Contains(inputColumns[i].LineageID))
{
inputColumns.RemoveObjectByIndex(i);
}
}
}
static private void AddLineageIdsFromExpression(IDTSCustomPropertyCollection100 columnProperties, ICollection<int> lineageIds)
{
int lineageId = 1;
var expressionProperty = columnProperties.Cast<IDTSCustomProperty100>().FirstOrDefault(p => p.Name == "Expression");
if (expressionProperty != null)
{
// Input columns used in expressions are always referenced as "#xxx" where xxx is the integer lineage ID.
var expression = expressionProperty.Value.ToString();
var expressionTokens = expression.Split(new[] { ' ', ',', '(', ')' });
foreach (var c in expressionTokens.Where(t => t.Length > 1 && t.StartsWith("#") && int.TryParse(t.Substring(1), out lineageId)))
{
if (!lineageIds.Contains(lineageId)) lineageIds.Add(lineageId);
}
}
}
Simple but not 100% Guaranteed Method
Call ReinitializeMetaData on the base component that EzApi is extending:
dc.Comp.ReinitializeMetaData();
This doesn't always respect some of the customizations and logic checks that EzAPI has, so test it carefully. For most vanilla components, though, this should work fine.
100% Guaranteed Method But Requires A Strategy For Identifying Columns To Ignore
You can set the UsageType property of those VirtualInputColumns to the enumerated value DTSUsageType.UT_IGNORED using EzApi's SetUsageType wrapper method.
But! You have to do this after you're done modifying any of the other metadata of your component (attaching other components, adding new input or output columns, etc.) since each of these triggers the ReinitializeMetaData method on the component, which automatically sets (or resets) all UT_IGNORED VirtualInputColumn's UsageType to UT_READONLY.
So some sample code:
// define EzSourceComponent with SourceColumnToIgnore output column, SomeConnection for destination
EzDerivedColumn dc = new EzDerivedColumn(this);
dc.AttachTo(EzSourceComponent);
dc.Name = "Errors, Go Away";
dc.InsertOutputColumn("NewDerivedColumn");
dc.Expression["NewDerivedColumn"] = "I was inserted!";
// Right here, UsageType is UT_READONLY
Console.WriteLine(dc.VirtualInputCol("SourceColumnToIgnore").UsageType.ToString());
EzOleDbDestination d = new EzOleDbDestination(f);
d.Name = "Destination";
d.Connection = SomeConnection;
d.Table = "dbo.DestinationTable";
d.AccessMode = AccessMode.AM_OPENROWSET_FASTLOAD;
d.AttachTo(dc);
// Now we can set usage type on columns to remove them from the available inputs.
// Note the false boolean at the end.
// That's required to not trigger ReinitializeMetadata for usage type changes.
dc.SetUsageType(0, "SourceColumnToIgnore", DTSUsageType.UT_IGNORED, false);
// Now UsageType is UT_IGNORED and if you saved the package and viewed it,
// you'll see this column has been removed from the available input columns
// ... and the warning for it has gone away!
Console.WriteLine(dc.VirtualInputCol("SourceColumnToIgnore").UsageType.ToString());
I was having exactly your problem and found a way to solve it. The problem is that the EzDerivedColumn has not the PassThrough defined in it's class.
You just need to add this to the class:
private PassThroughIndexer m_passThrough;
public PassThroughIndexer PassThrough
{
get
{
if (m_passThrough == null)
m_passThrough = new PassThroughIndexer(this);
return m_passThrough;
}
}
And alter the ReinitializeMetadataNoCast() to this:
public override void ReinitializeMetaDataNoCast()
{
try
{
if (Meta.InputCollection[0].InputColumnCollection.Count == 0)
{
base.ReinitializeMetaDataNoCast();
LinkAllInputsToOutputs();
return;
}
Dictionary<string, bool> cols = new Dictionary<string, bool>();
foreach (IDTSInputColumn100 c in Meta.InputCollection[0].InputColumnCollection)
cols.Add(c.Name, PassThrough[c.Name]);
base.ReinitializeMetaDataNoCast();
foreach (IDTSInputColumn100 c in Meta.InputCollection[0].InputColumnCollection)
{
if (cols.ContainsKey(c.Name))
SetUsageType(0, c.Name, cols[c.Name] ? DTSUsageType.UT_READONLY : DTSUsageType.UT_IGNORED, false);
else
SetUsageType(0, c.Name, DTSUsageType.UT_IGNORED, false);
}
}
catch { }
}
That is the strategy used by other components. If you want to see all the code you can check my EzApi2016#GitHub. I'm updating the original code from Microsoft to SQL Server 2016.

Hiding initial value in Imported Database Model of Enterprise Architect

I am currently creating database model by doing reverse-engineering MS SQL Server 2008 into Sparx's Enterprise Architect version 10.
I have been able to import tables, and hide items that are not required (such operations and stereotypes). However, I did not find the option to hide for Column Initial values when importing tables or in diagram properties, which left me the option to edit each column one by one (time consuming).
Do I miss any configuration to hide the Initial value? If such configuration does not exist, what is the best method to hide/remove the Initial value without configuration?
Finally got the solution by creating EA script. Feels free to use and enhance it :)
!INC Local Scripts.EAConstants-JScript
function OnProjectBrowserScript()
{
// Show the script output window
Repository.EnsureOutputVisible( "Script" );
var treeSelectedType = Repository.GetTreeSelectedItemType();
switch ( treeSelectedType )
{
case otElement: // if select table
{
removeInitial(Repository.GetContextObject());
break;
}
case otPackage: // if select package containing table
{
var selectedObject as EA.Element;
selectedObject = Repository.GetContextObject();
for ( var i = 0 ; i < selectedObject.Elements.Count ; i++ )
{
removeInitial(selectedObject.Elements.GetAt( i ));
}
break;
}
default:
{
// Error message
Session.Prompt( "This script does not support items of this type.", promptOK );
}
}
}
function removeInitial(selectedObject)
{
for (var i = 0 ; i < selectedObject.Attributes.Count; i++)
{
var attrib as EA.Attribute;
attrib = selectedObject.Attributes.GetAt(i);
attrib.Default = "";
attrib.Update();
}
Session.Output("finished updating " + selectedObject.Name);
}
OnProjectBrowserScript();

SQLBulkCopy with Identity Insert in destination table

I am trying to insert a Generic list to SQL Server with SQLBulkCopy,
And i have trouble wit Identity Field
I wan t my destination table to generate identity field
How should i handle this,
here is my code
using (var bulkCopy = new SqlBulkCopy(ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString))
{
bulkCopy.BatchSize = (int)DetailLines;
bulkCopy.DestinationTableName = "dbo.tMyTable";
var table = new DataTable();
var props = TypeDescriptor.GetProperties(typeof(tBFFormularyStatusList))
//Dirty hack to make sure we only have system data types
//i.e. filter out the relationships/collections
.Cast<PropertyDescriptor>()
.Where(propertyInfo => propertyInfo.PropertyType.Namespace.Equals("System"))
.ToArray();
foreach (var propertyInfo in props)
{
bulkCopy.ColumnMappings.Add(propertyInfo.Name, propertyInfo.Name);
table.Columns.Add(propertyInfo.Name, Nullable.GetUnderlyingType(propertyInfo.PropertyType) ?? propertyInfo.PropertyType);
}
var values = new object[props.Length];
foreach (var item in myGenericList)
{
for (var i = 0; i < values.Length; i++)
{
values[i] = props[i].GetValue(item);
}
table.Rows.Add(values);
}
bulkCopy.WriteToServer(table);
}
exception
Property accessor 'ID' on object 'ProcessFlatFiles.DetailsClass' threw the following exception:'Object does not match target type.'
I have also tried
using (var bulkCopy = new SqlBulkCopy(ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString, SqlBulkCopyOptions.KeepIdentity))
{
Finally I got this worked this way
using (var bulkCopy = new SqlBulkCopy(ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString, SqlBulkCopyOptions.KeepNulls & SqlBulkCopyOptions.KeepIdentity))
{
bulkCopy.BatchSize = (int)DetailLines;
bulkCopy.DestinationTableName = "dbo.myTable";
bulkCopy.ColumnMappings.Clear();
bulkCopy.ColumnMappings.Add("SourceColumnName", "DestinationColumnName");
bulkCopy.ColumnMappings.Add("SourceColumnName", "DestinationColumnName");
bulkCopy.ColumnMappings.Add("SourceColumnName", "DestinationColumnName");
bulkCopy.ColumnMappings.Add("SourceColumnName", "DestinationColumnName");
.
.
.
.
bulkCopy.ColumnMappings.Add("SourceColumnName", "DestinationColumnName");
bulkCopy.WriteToServer(datatable);
}
I know this is an old question, but I thought it was worth adding this alternative:
(If you already have correct schema, can skip 1,2,3)
Perform a simple TOP 1 select from the table to return the a datatable with the destination table's schema
Use DataTable's Clone method to generate a datatable with same schema and no data
Insert your data into this table
Perform SqlBulkCopy's WriteToServer (if column orders match, then the identity values can be read. If the option isn't provided in SqlBulkCopy's constructor then the default is to ignore these values and let the destination provide them).
The important point is that if you have the columns in the correct order (including identity columns), everything is handled for you.

Linq-to-SQL with a table valued UDF user defined function

I am new to Linq and trying to get a handle on how to bind a drop down to a SQL user defined function.
//Populate the Pledge dropdown
var db = new App_Data.MyDBDataContext();
int? partnerID = Convert.ToInt32(Request.QueryString["PartnerID"]);
var pledges =
from p in db.ufn_AvailablePledgesByPartner(partnerID)
select new
{
PledgeAndPartnerName = p.PledgeAndPartnerName,
PledgeID = p.PledgeID
};
DropDownList ddlPledgeID = (DropDownList)DetailsViewContribution.FindControl("DropDownListPledgeID");
ddlPledgeID.DataSource = pledges;
ddlPledgeID.DataTextField = pledges.PledgeAndPartnerName;
ddlPledgeID.DataValueField = pledges.PledgeID;
The current problem is the last 2 lines where I'm trying to reference properties of the anonymous class. "'System.Linq.IQueryable' does not contain a definition for 'PledgeAndPartnerName' and no extension method..." I naively thought the compiler was supposed to figure this out, but obviously I'm assuming C# is now more dynamic than it really is.
Thanks for any input.
Try this:
ddlPledgeID.DataTextField = "PledgeAndPartnerName";
ddlPledgeID.DataValueField = "PledgeID";