I have made a FetchXML query that returns data from my CRM2013 grid
The data is passed into a list
Which is then turned into a CSV file with the following code;
EntityCollection result = service.RetrieveMultiple(new FetchExpression(fetchxml)); foreach (var c in result.Entities)
{
if (result != null && result.Entities.Count > 0)
{
List<string> _product = new List<string>();
foreach (Entity _entity in result.Entities)
{
_product.Add(((EntityReference)c.Attributes["productid"]).Name.ToString());
_product.Add(_entity.Attributes["quantity"].ToString());
}
CSVFile = string.Join(",", _product.ToArray());
string AddressPath = "FM-OR" + "_";
string AddressSavePath = #"\\fm\CRMdata\maesteg\" + AddressPath + ".csv";
System.IO.File.WriteAllText(AddressSavePath, CSVFile.ToString());
The output would be as follows
ProductExample1, 1.0, ProductExample2, 4.0, ProductExample3, 2.0
What I want is the output to now be
ProductExample1, 1.0
ProductExample2, 4.0
ProductExample3, 2.0
Any suggestions at how I would achieve this?
Thanks
Update
Didn't feel like I quite explained it properly
With the output I want, I want them to be separate strings so that I can output a different CSV file for each Product + Quantity in the list
Thanks
Update
Code with new suggestions implemented, error is described in comment below
EntityCollection result = service.RetrieveMultiple(new FetchExpression(fetchxml)); foreach (var c in result.Entities)
{
if (result != null && result.Entities.Count > 0)
{
List<string> _product = new List<string>();
foreach (Entity _entity in result.Entities)
{
string productid = (((EntityReference)_entity.Attributes["productid"]).Name.ToString());
string quantity = _entity.Attributes["quantity"].ToString();
CSVFile = productid + "," + quantity;
int n =1;
string AddressPath = "FM-OR" + "_" +actualID + "_" + n;
string AddressSavePath = #"\\fm\CRMdata\maesteg\" + AddressPath + ".csv";
System.IO.File.WriteAllText(AddressSavePath, CSVFile.ToString());
n++;
}
}
}
Thanks
From what I understand of your question, this might help you. CSVFILE now is a string containing the productid and quantity separated by a "," which you can write to your file.
EntityCollection result = service.RetrieveMultiple(new FetchExpression(fetchxml));
if (result != null && result.Entities.Count > 0)
{
List<string> _products = new List<string>();
foreach (Entity _entity in result.Entities)
{
string productid = (EntityReference)c.Attributes["productid"]).Name.ToString();
string quantity = _entity.Attributes["quantity"].ToString();
CSVFILE = productid + "," + quantity;
//Write CSVFILE
//...
}
}
What about such an extension method?
public static IEnumerable<string> JoinEverySecond(this IList<string> list)
{
if (list == null)
{
throw new ArgumentNullException("list");
}
for (var i = 0; i < list.Count; i += 2)
{
if (i + 1 >= list.Count)
{
yield return list[i];
}
yield return string.Join(",", list[i], list[i + 1]);
}
}
Warn: not tested, but I wanted just to present the idea.
Related
Receiving the error:
CS0029: Cannot implicitly convert type 'System.Collections.Generic.List' to 'int'
Not sure how to fix.
I am using:
Microsoft .NET Framework Version:2.0.50727.5477;
ASP.NET Version:2.0.50727.5479
Section that's giving me trouble is at:
{
debugStr = debugStr + "-a=noattributesadd";
CartItem item = new CartItem(context);
item.ProductId = product.ProductId;
item.Quantity = qty;
items.Add(item);
}
Specifically, the item.Quantity = qty; portion
Complete code is:
CartItemCollection items = new CartItemCollection();
Cart cart = Core.GetCartObject();
string skus = "";
string debugStr = "";
Product product = null;
List<int> qty = new List<int>();
foreach (string item in HttpContext.Current.Request.Form.GetValues("quantity_input"))
{
qty.Add(int.Parse(item));
}
try
{
string[] productNumbers = HttpContext.Current.Request.Form.GetValues("ProductNumber");
foreach (string productNumber in productNumbers)
{
debugStr = debugStr + "-p=" + productNumber;
if(!string.IsNullOrEmpty(productNumber.Trim()) && !productNumber.StartsWith("Enter Product #"))
{
try
{ //redirect if no product found
product = Core.GetProductObjectByProductNumber(productNumber);
}
catch (Exception e)
{
debugStr = debugStr + "-e=noproductfound";
continue; //do nothing, process the next user input
}
//check if we have a valid product object, allow virtual and other type(s) for adding directly to cart which may need special handling
if(product != null)
{
debugStr = debugStr + "-t=" + product.ProductTypeName;
if(!product.ProductTypeName.Equals("NORMAL"))
{
//assume VIRTUAL (or other type) and redirect for selecting child/group products or other special handling
form.Redirect("product.aspx?p=" + product.ProductNumber);
}
else
{
debugStr = debugStr + "-a=noattributesadd";
CartItem item = new CartItem(context);
item.ProductId = product.ProductId;
item.Quantity = qty;
items.Add(item);
}
skus = skus + ";" + productNumber;
product = null; //reset the product object in case the next product number submitted is invalid
} //product not null
} //sanity check for empty or default data
} //iterate on each product submitted
cart.AddItems(items);
form.Redirect("cart.aspx?skus=" + skus);
}
catch (Exception e)
{
form.AddError("*** ProductNumber provided was not found ***");
form.Redirect("quickorder.aspx?qo=2&e=" + e.Message);
return;
}
Essentially, this is the logic for a Quick Order form. I'm trying to add the qty of each item to the Cart.
You problem is in this line:
item.Quantity = qty;
item.Quantity is an int and qty is a List<int>
A guess at how to solve (assume all lists are in the same order and enumeration will read them in the same order):
int index = 0; // add this line
foreach (string productNumber in productNumbers)
{
// all the stuff you have already till:
item.Quantity = qty[index];
// all the stuff you have already
index = index + 1;
} //iterate on each product submitted
NOTE: I HATE THIS SOLUTION. But it will probably work.
A good solution would be to create a data structure that holds both the productnumber and the quantity in the same list.
string sStoreStockFeed = "";
string sSeparator = "";
var distinctStoreIDList = skuStoreStockLevels.Select(x => x.Item1).Distinct();
foreach (var storeID in distinctStoreIDList)
{
foreach (var item in skuStoreStockLevels)
{
if (item.Item1 == storeID)
{
// add this one to a job for this store
sStoreStockFeed += sSeparator + item.Item1.ToString() + "," + item.Item2.ToString() + "," + item.Item3.ToString();
sSeparator = "|";
}
}
// some code to process the string before moving on
sStoreStockFeed = "";
sSeparator = "";
}
In the above code snippet skuStoreStockLevels just happens to be a List of type Tuple and Item1 is the StoreID. having got a distinct list it then iterates through the (non-distinct) list to get every applicable item. The inefficiency is that the (big) inner list is iterated throuh repeatedly for each distinct item (StoreID).
UPDATE: pure LINQ solution. This will give you list of strings, created for each group of items.
var query = skuStoreStockLevel.GroupBy(x => x.Item1)
.Select(g => g.Aggregate(new StringBuilder(),
(sb, x) => sb.AppendFormat("{0}{1},{2},{3}", sSeparator, x.Item1, x.Item2, x.Item3),
(sb) => sb.ToString()));
foreach(var feed in query)
// some code to process the string before moving on
Also there are other options - ordering of sequence. Equal items will follow one after another.
int storeID = -1;
StringBuilder builder = new StringBuilder();
foreach (var item in skuStoreStockLevel.OrderBy(x => x.Item1))
{
builder.AppendFormat("{0}{1},{2},{3}", sSeparator, item.Item1, item.Item2, item.Item3);
if (item.Item1 != storeID)
{
// some code to process the string before moving on
storeID = item.Item1;
}
}
Or you can use grouping
StringBuilder builder = new StringBuilder();
foreach (var storeGroup in skuStoreStockLevel.GroupBy(x => x.Item1))
{
foreach (var item in storeGroup)
builder.AppendFormat("{0}{1},{2},{3}", sSeparator, item.Item1, item.Item2, item.Item3);
// some code to process the string before moving on
}
And, of course, it's better to use StringBuilder for creating strings.
Use Linq GroupBy which will build you a list of grouped items:
string sStoreStockFeed = "";
string sSeparator = "";
var itemsByStore = skuStoreStockLevels.GroupBy(x => x.Item1);
foreach (var storeItems in itemsByStore )
{
// storeItems.Key is the storeId, that is x.Item1
foreach(var item in storeItems)
{
sStoreStockFeed += sSeparator + item.Item1.ToString() + "," + item.Item2.ToString() + "," + item.Item3.ToString();
sSeparator = "|";
}
// some code to process the string before moving on
sStoreStockFeed = "";
sSeparator = "";
}
is it possible to convert data table to ienumerable without know its class name.
my requirement is to convert table
First | Last
--------------
john | mcgill
clara | linda
to
{{First:john,Last:mcgill},{First:clara ,Last:linda}}
Ienumerable collection
i dont want to use dynamic object because dynamic object supports only frame work 4.
thanks
var results = from row in dataTable.AsEnumerable()
select new {
First = row.Field<string>("First"),
Last = row.Field<string>("Second")
};
You'll need System.Data.DataSetExtensions.
You can use Anonymous Types - they were introduced with .NET 3.5.
Syntax for that kind of objects is really clear and intuitive:
var item = new { First = "First-Value", Last = "Last-Value" }
and the query:
var items = dataTable.AsEnumerable()
.Select(i => new {
First = i.Field<string>("First"),
Last= i.Field<string>("Last")
});
No column names please!
public string ConvertDataTableToString(DataTable table)
{
int iColumnCount = table.Columns.Count;
int iRowCount = table.Rows.Count;
int iTempRowCount = 0;
string strColumName = table.Columns[0].ColumnName;
string strOut = "{";
foreach (DataRow row in table.Rows)
{
strOut = strOut + "{";
foreach (DataColumn col in table.Columns)
{
string val = row.Field<string>(col.ColumnName);
strOut = strOut + col.ColumnName + ":" + val;
if (col.Ordinal != iColumnCount - 1)
{
strOut = strOut + ",";
}
}
strOut = strOut + "}";
iTempRowCount++;
if (iTempRowCount != iRowCount)
{
strOut = strOut + ",";
}
}
strOut = strOut + "}";
return strOut;
}
It is a fairly easy job using anonymous types. Here is a complete example that only requires classes from the System.Linq and System.Data namespaces:
class Program
{
static void Main(string[] args)
{
DataTable dataTable = new DataTable();
dataTable.Columns.Add().ColumnName = "First";
dataTable.Columns.Add().ColumnName = "Last";
var row = dataTable.NewRow();
row["First"] = "hello";
row["Last"] = "world";
dataTable.Rows.Add(row);
var query = dataTable.Rows.Cast<DataRow>()
.Select(r => new
{
First = r["First"],
Last = r["Last"]
});
foreach (var item in query)
Console.WriteLine("{0} {1}", item.First, item.Last);
}
}
not sure why i get the above error, i know its because of UpdateWorkflowAssociation is inside the foreach but i need it that way
A simple help will be highly appreciated
`siteName = "http://xyz";
newCleanupDays = 5;
assoCounter = 0;
using (wfSite = new SPSite(siteName))
{
using (wfWeb = wfSite.OpenWeb())
{
//wfList = wfWeb.Lists[libraryName];
SPListCollection collList = wfWeb.Lists; //Open Lists
SPWorkflowAssociation _wfAssociation = null;
foreach (SPList oList in collList)
{
if (oList.WorkflowAssociations.Count > 0)
{
foreach (SPWorkflowAssociation a in oList.WorkflowAssociations)
{
if (a.Name != null || a.Name != string.Empty)
{
a.AutoCleanupDays = newCleanupDays;
_wfAssociation = a;
assoCounter++;
}
else
{
_wfAssociation = a;
}
}
oList.UpdateWorkflowAssociation(_wfAssociation);
}
}
System.Console.WriteLine("\n" + wfAssoName + ": " + assoCounter.ToString() + " workflow association(s) changed successfuly!\n");
}
}`
Instead of
foreach (SPList oList in collList)
simply write
foreach (SPList oList in collList.ToList())
That way you will iterate over a copy which is not modified during the iteration, but the real collection can be updated.
is there an elegant object-orient based framework?
Here is some code that I wrote for generating 'insert' stored procedures for every table in a database. It also handles returning the new id for those tables that have an identity column. It uses SQL SMO. Some of it is a bit specific to my project so please let me know if you have any questions.
void InsertScripts(Database db)
{
var tables = db.Tables.ToIEnumerable(); //this is an extension method to convert Database.Tables into an IEnumerable<Table>
{
foreach (var t in tables)
{
var sb = new StringBuilder();
var sp = new StoredProcedure(db, "gen_insert_" + t.Name);
sp.AnsiNullsStatus = false;
sp.QuotedIdentifierStatus = false;
sp.TextMode = false;
var columns = t.Columns.ToIEnumerable().Where(c => !c.Identity && !c.IsReadOnly()).ToList();
foreach (var c in columns)
{
var p = new StoredProcedureParameter(sp, "#" + t.Name + "_" + c.Name, c.DataType);
p.IsCursorParameter = false;
if(c.Default != null && c.Default.Length > 0)
p.DefaultValue = c.Default;
if (c.Nullable)
p.DefaultValue = "NULL";
sp.Parameters.Add(p);
}
var cols = string.Join(",", columns.Select(c => c.Name).ToArray());
var vals = string.Join(",", columns.Select(c => "#" + t.Name + "_" + c.Name).ToArray());
var sql = string.Format("insert into {0} ({1}) values ({2});", t.Name, cols, vals);
sb.AppendLine(sql);
if (t.Columns.ToIEnumerable().Any(c => c.Identity))
{
var declaration = "declare #newid int;\r\n";
var ret = "select #newid = scope_identity();\r\nselect #newid;\r\nreturn #newid";
sb.Insert(0, declaration);
sb.AppendLine(ret);
}
sp.TextBody = sb.ToString();
if(cols.Length > 0 && sp.Parent.StoredProcedures[sp.Name] == null)
sp.Create();
}
}
}
public static class Utils //Extension methods...
{
public static IEnumerable<Table> ToIEnumerable(this TableCollection tables)
{
var list = new List<Table>();
foreach (Table t in tables)
list.Add(t);
return list;
}
public static IEnumerable<View> ToIEnumerable(this ViewCollection views)
{
var list = new List<View>();
foreach (View v in views)
list.Add(v);
return list;
}
public static IEnumerable<Column> ToIEnumerable(this ColumnCollection columns)
{
var list = new List<Column>();
foreach (Column c in columns)
list.Add(c);
return list;
}
public static IEnumerable<ForeignKey> ToIEnumerable(this ForeignKeyCollection columns)
{
var list = new List<ForeignKey>();
foreach (ForeignKey c in columns)
list.Add(c);
return list;
}
public static IEnumerable<string> ToIEnumerable(this ForeignKeyColumnCollection columns)
{
var list = new List<string>();
foreach (ForeignKeyColumn c in columns)
list.Add(c.Name);
return list;
}
}
It sounds like you want an ORM, or do you actually want the insert text rather than inserting?
You should give Linq To SQL a look.
I just wrote a quick n dirty data export script (for thoose times you can't access the db via SSMS). Anyway, this might help someone in the future:
var result = new StringBuilder();
using (var con = new SqlConnection(ConfigurationManager.ConnectionStrings["MyConnectionString"].ConnectionString)) {
con.Open();
using (var cmd = con.CreateCommand()) {
cmd.CommandText = #"
DECLARE #name VARCHAR(255)
DECLARE iterator CURSOR FOR SELECT name FROM sys.tables WHERE type='U'
OPEN iterator
FETCH NEXT FROM iterator INTO #name
WHILE ##FETCH_STATUS = 0 BEGIN
SELECT #name name
EXEC ('SELECT * FROM ' + #name)
FETCH NEXT FROM iterator INTO #name
END
CLOSE iterator
DEALLOCATE iterator
";
using (var reader = cmd.ExecuteReader()) {
do {
// get table name
reader.Read();
string tableName = reader[0].ToString();
// get contents
reader.NextResult();
result
.Append("SET IDENTITY_INSERT ")
.Append(tableName)
.Append(" ON\r\n");
while (reader.Read()) {
result
.Append("INSERT ")
.Append(tableName)
.Append(" (");
for (var x = 0; x < reader.FieldCount; x++)
result
.Append(x == 0 ? string.Empty : ",")
.Append("[" + reader.GetName(x) + "]");
result
.Append(" ) VALUES (");
for (var x = 0; x < reader.FieldCount; x++)
result
.Append(x == 0 ? string.Empty : ",")
.Append("'" + reader[x].ToString() + "'");
result
.Append(")\r\n");
}
result
.Append("SET IDENTITY_INSERT ")
.Append(tableName)
.Append(" OFF\r\n");
} while (reader.NextResult());
}
}
}
Response.Write(result);