Is it possible to return IEnumerable of anonymous objects from DataContext.ExecuteQuery? - linq

I develop a reporting engine where reports are based on templates. Every template has string with SQL query and every report has specific values for SQL query parameters. To render a report I set parameters and call DataContext.ExecuteQuery method to get list of records. But to catch returned columns I have to know their names and have a class with corresponding properties.
Is it possible somehow to return IEnumerable of anonymous objects from DataContext.ExecuteQuery and then determine their properties using Reflection?
I need a LINQ equivalent for SqlDataReader.GetValues.
Thanks!

Until we have C# 4.0 with dynamiс keyword we can use this solution (slightly modified code from an article Executing arbitrary queries in LINQ to SQL by Octavio Hernández Leal):
public static class DataContextExtension
{
public static IEnumerable<Dictionary<string, object>> ExecuteQuery(this DataContext dataContext, string query)
{
using (DbCommand command = dataContext.Connection.CreateCommand())
{
command.CommandText = query;
dataContext.Connection.Open();
using (DbDataReader reader = command.ExecuteReader(CommandBehavior.CloseConnection))
{
while (reader.Read())
{
Dictionary<string, object> dictionary = new Dictionary<string, object>();
for (int i = 0; i < reader.FieldCount; i++)
dictionary.Add(reader.GetName(i), reader.GetValue(i));
yield return dictionary;
}
}
}
}
}
This extension method returns IEnumerable of Dictionary<> objects where keys are names of query columns.

Yes, you can do it.
Please have a look at this snippet.
class Program {
static void Main(string[] args) {
var persons = new Person[]{
new Person{Age=22,Name="John Doe",Id=1},
new Person{Age=23,Name="Jack Smith", Id=2},
new Person{Age=34,Name="Sara Parker", Id=3}
};
var anonData = GetAnonTypes(persons);
foreach (var item in anonData as IEnumerable) {
//use reflection to access propties
}
}
static object GetAnonTypes(IEnumerable<Person> persons) {
var query=from p in persons select new{
Id=p.Id,
Name=p.Name
};
return query;
}
}
public class Person {
public int Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
}

Related

Passing variables / arguments between repeated Activities in MassTransit Courier Routing Slips

I'm looking to integrate the MassTransit Courier Routing Slip features into an existing solution using Azure Functions and ServiceBusTriggers that synchronizes data between two systems, and has to use a SOAP HTTP client. However, I'm struggling to understand how arguments and variables passed between activities are prioritized. This is best explained via a poor mock example itinerary. My assumption was that variables override existing arguments, but I think that was an incorrect assumption.
public class SyncCustomerOrderConsumer : IConsumer<SyncCustomerOrderMessage>
{
public async Task Consume(ConsumeContext<SyncCustomerOrderMessage> context)
{
var slip = this.BuildRoutingSlip(context.Message);
await context.Execute(slip);
}
private RoutingSlip BuildRoutingSlip(SyncCustomerOrderMessage args)
{
var builder = new RoutingSlipBuilder(NewId.NextGuid());
builder.AddVariable("OrderItems", args.OrderItems);
builder.AddActivity(nameof(SyncCustomerActivity), GetActivityCustomer<SyncCustomerActivity, SyncCustomerArgs>() new {
args.Customer
});
builder.AddActivity(nameof(SyncCustomerActivity), GetActivityCustomer<SyncCustomerActivity, SyncCustomerArgs>() new {
args.ShippingAddress
});
builder.AddActivity(nameof(SyncOrderActivity), GetActivityCustomer<SyncOrderActivity, SyncOrderArgs>() new {
args.Order
});
foreach (var item in args.OrderItems)
{
builder.AddActivity(nameof(SyncOrderItemActivity), GetActivityCustomer<SyncOrderItemActivity, SyncOrderItemArgs>(), new
{
OrderItem = args.item
});
}
builder.AddActivity(nameof(SyncSourceActivity), GetActivityCustomer<SyncSourceActivity, SyncSourceArgs>());
return builder.Build();
}
}
public class SyncOrderItemActivity : IExecuteActivity<SyncOrderItemArgs>
{
private readonly IOrderItemWebserviceClient _client;
privater readonly IMapper _mapper;
public SyncOrderItemActivity(IOrderItemWebserviceClient client, IMapper mapper)
{
_client = client;
_mapper = mapper;
}
public async Task<ExecutionResult> Execute(ExecuteContext<SyncOrderItemArgs> context)
{
var args = context.Arguments;
var dto = _mapper.Map<OrderItemDto>(args);
if (args.OrderItem.External.IsNotSynced())
{
var response = await _client.AddAsync(dto);
args.OrderItem.ExternalId = response.Uuid;
args.OrderItem.LastSynced = response.LastUpdated;
}
else
{
var response = await _client.UpdateAsync(dto);
args.OrderItem.LastSynced = response.LastUpdated;
}
// replace the existing order items variable
int index = args.OrderItems.FindIndex(oi => oi.Id == args.OrderItem.Id);
if (index != 1)
args.OrderItems[index] = orderItem;
return context.CompletedWithVariables(new { OrderItem = args.OrderItem, OrderItems = args.OrderItems });
}
}
public class SyncOrderItemArgs
{
public OrderItem OrderItem { get; set; }
public List<OrderItem> OrderItems { get; set; }
}
public class SyncSourceActivity : IExecuteActivity<SyncSourceArgs>
{
private readonly IEventGridClient _client;
privater readonly IMapper _mapper;
public SyncSourceActivity(IEventGridClient client, IMapper mapper)
{
_client = client;
_mapper = mapper;
}
public async Task<ExecutionResult> Execute(ExecuteContext<SyncSourceArgs> context)
{
var args = context.Arguments;
// this is the original list, not the replaced list
foreach (var item in args.OrderItems)
{
await _client.PublishAsync(new OrderItemSyncedEvent { item });
}
return context.Completed();
}
}
public class SyncCustomerOrderMessage
{
public Customer Customer { get; set; }
public Order Order { get; set; }
public List<OrderItem> OrderItems { get; set; }
public Address ShippingAddress { get; set; }
}
The problem here is that the list of activities to deal with each OrderItem is defined as an argument and updated in each call to that SynOrderItemactivity. As the individual item is processed, it is supposed to replace the original item in the list and then pass the entire altered list as a variable into the next iteration of the same activity. However, the list is not the altered list, but the original one.
I guess my question is two-fold:
How do should you best design a routing slip that has a a list if the same activity, where some of the arguments have to be defined, but others are expected to come from the variable?
When it comes to arguments and variables, which ones take priority?
Unknown? I'm not even sure what this question is asking.
Arguments first, variables second. Explicitly specified arguments when adding the activity to the itinerary take precedence, missing arguments are pulled from variables if present, or left at the default/null value.

csvHelper Sort field while writing

I am trying to use CsvHelper library to write CSV stream to a file. All is well however I am stuck with 2 things
How do I add additional columns to the csv file. The additional column value will be a constant but will only be known at runtime.
Is there a way to sort the CSV file on a particular field if I am writing one record at a time and also when I am writing all at once
static void Main(string[] args)
{
var records = new List<MyTest>
{
new MyTest { Id = 1, Name = "John", Extra = "hello" },
new MyTest { Id = 2, Name = "Jack", Extra = "hi" },
};
using (var writer = new StreamWriter("C:\\Users\\machina\\AppData\\Local\\Temp\\file.csv"))
using (var csv = new CsvWriter(writer, CultureInfo.InvariantCulture))
{
csv.Context.RegisterClassMap<TestMap<MyTest>>();
csv.WriteRecords<MyTest>(records);
}
}
}
public interface IData
{
public int Id { get; set; }
public string Name { get; set; }
}
public abstract class AbTest : IData
{
public abstract int Id { get; set; }
public abstract string Name { get; set; }
public abstract string Extra { get; set; }
}
public class MyTest : AbTest
{
public override int Id { get; set; }
public override string Name { get; set; }
public override string Extra { get; set; }
}
public class TestMap<T> : ClassMap<MyTest>
{
public TestMap()
{
AutoMap(CultureInfo.InvariantCulture);
}
}
The above works as I have prepared the data records however what I want to achieve is to dynamically add Extra column values to my existing stream of csv data which does not have it.
Also I saw DynamicPropertySort under csvconfiguration and wanted to check if this can be used in any way to sort the fields in my CSV stream before its written even when its writing one record at a time?
I am a novoice developer so let me know if there is a better way to achieve this.
The easiest way to dynamically add columns would likely be to manually write out each row.
DynamicPropertySort is just used for ordering the columns of a dynamic object. You can sort on a particular field using the linq OrderBy() method.
static void Main(string[] args)
{
var records = new List<MyTest>
{
new MyTest { Id = 1, Name = "John", Extra = "hello" },
new MyTest { Id = 2, Name = "Jack", Extra = "hi" },
};
var extraField1 = 10;
var extraField2 = "Testing";
using (var writer = new StreamWriter("C:\\Users\\machina\\AppData\\Local\\Temp\\file.csv"))
using (var csv = new CsvWriter(writer, CultureInfo.InvariantCulture))
{
csv.Context.RegisterClassMap<TestMap>();
var orderedRecords = records.OrderBy(r => r.Name);
csv.WriteHeader<MyTest>();
csv.WriteField("ExtraField1");
csv.WriteField("ExtraField2");
csv.NextRecord();
foreach (var record in orderedRecords)
{
csv.WriteRecord(record);
csv.WriteField(extraField1);
csv.WriteField(extraField2);
csv.NextRecord();
}
}
}

Insertion operation in SqlCe in windows phone

I am trying to insert some data into mydatabase but getting error like "Can't perform Create, Update, or Delete operations on 'Table(Dic)' because it has no primary key."
My database name is "condrokotha_new.sdf" and it has a table named "dic" which have 2 columns named "english" and "bangla". I made this database in another C# project in vs 2010. Then i used this database into my windowsphone project. I can show data from database but when i try to insert data i am getting error.
Here is my code:
public partial class MainPage : PhoneApplicationPage
{
condrokotha_newContext db = null;
// Constructor
public MainPage()
{
InitializeComponent();
db = new condrokotha_newContext(condrokotha_newContext.ConnectionString);
db.CreateIfNotExists();
db.LogDebug = true;
}
private void fav_Click(object sender, RoutedEventArgs e)
{
add_new_words("cintakhela","ami");
}
private void add_new_words(string e_word,string b_word)
{
using (condrokotha_newContext context = new condrokotha_newContext(condrokotha_newContext.ConnectionString))
{
Dic d = new Dic();
d.English = e_word;
d.Bangla = b_word;
context.Dics.InsertOnSubmit(d);
context.SubmitChanges();
}
}
}
My data context code like these :
public static string ConnectionString = "Data Source=isostore:/condrokotha_new.sdf";
public static string ConnectionStringReadOnly = "Data Source=appdata:/condrokotha_new.sdf;File Mode=Read Only;";
public static string FileName = "condrokotha_new.sdf";
public condrokotha_newContext(string connectionString) : base(connectionString)
{
OnCreated();
}
#region Extensibility Method Definitions
partial void OnCreated();
#endregion
public System.Data.Linq.Table<Dic> Dics
{
get
{
return this.GetTable<Dic>();
}
}
}
[global::System.Data.Linq.Mapping.TableAttribute(Name="dic")]
public partial class Dic
{
private string _English;
private string _Bangla;
public Dic()
{
}
[global::System.Data.Linq.Mapping.ColumnAttribute(Name="english", Storage="_English", DbType="NVarChar(1000)")]
public string English
{
get
{
return this._English;
}
set
{
if ((this._English != value))
{
this._English = value;
}
}
}
[global::System.Data.Linq.Mapping.ColumnAttribute(Name="bangla", Storage="_Bangla", DbType="NText", UpdateCheck=UpdateCheck.Never)]
public string Bangla
{
get
{
return this._Bangla;
}
set
{
if ((this._Bangla != value))
{
this._Bangla = value;
}
}
}
}
`
How can i insert my data into my database??
Is there anyone who can help in this??
For example you have this
SampleDataContextDataContext db = new SampleDataContextDataContext();
Employee emp = new Employee() {
FirstName = "Experts",
Lastname = "Comment",
Address = "rs.emenu#gmail.com"
}
db.Employees.InsertOnSubmit(emp);
db.SubmitChanges();
The above code will give you same error when u try to insert a new row. The reason is that LINQ does not provide the facility to insert data into a table without a primary key. At this point you have two options.
1.Create a store procedure and call it from LINQ.
SampleDataContextDataContext db = new SampleDataContextDataContext();
db.InsertEmployeeData("Experts","Comment", "rs.emenu#gmail.com");
Here InsertEmployeeData is a a stored procedure, and called it from the code.
2.Create an insert statement and execute using LINQ.
SampleDataContextDataContext db = new SampleDataContextDataContext();
string insertStatement = "Insert into Employee values('Experts', 'Comment','rs.emenu#gmail.com')";
db.ExecuteQuery<Employee>(insertStatement);
Here insert query is normal sql query and executed using the the LINQ ExecuteQuery method.

ASMX Web Service, Stored Procedures and MVC Models

I am developing a web application using MVC 3. This application connects to an SQL Server database through ASMX Web Services. Each Web Method calls a Stored Procedure and returns a DataTable.
This is the code I'm using to call the Stored Procedure:
public static DataTable ExecSP(string StoredProcedureName, List<string> ParameterNames, List<Object> ParameterValues)
{
SqlConnection Connection = new SqlConnection(ConfigurationManager.ConnectionStrings["SQLServer"].ConnectionString);
SqlDataReader Reader = null;
DataTable SPResult = null;
try
{
Connection.Open();
SqlCommand Command = new SqlCommand("dbo." + StoredProcedureName, Connection);
Command.CommandType = CommandType.StoredProcedure;
if (ParameterNames != null)
{
for (int i = 0; i < ParameterNames.Count; i++)
{
SqlParameter Parameter = new SqlParameter(ParameterNames[i], ParameterValues[i]);
if (Parameter.SqlDbType.Equals(SqlDbType.NVarChar))
{
Parameter.SqlDbType = SqlDbType.VarChar;
}
if (Parameter.SqlValue == null)
{
Parameter.SqlValue = DBNull.Value;
}
Command.Parameters.Add(Parameter);
}
}
Reader = Command.ExecuteReader();
SPResult = new DataTable();
SPResult.Load(Reader);
}
catch (Exception ex)
{
throw;
}
finally
{
Connection.Close();
if (Reader != null)
{
Reader.Close();
}
}
return SPResult;
}
I would like to know if there is a straight-forward way to convert this DataTable into a Model that can then be passed to a View (like, for example, the model binding that happens in an AJAX post) and, if there isn't, what are the alternatives. I know that using LINQ would probably solve this problem, but I can't use it.
Thanks in advance.
Best regards.
Found a solution.
I built a generic method that translates any DataTable into a List of whatever class I specify:
public static List<T> Translate<T>(DataTable SPResult, Func<object[],T> del)
{
List<T> GenericList = new List<T>();
foreach (DataRow Row in SPResult.Rows)
{
GenericList.Add(del(Row.ItemArray));
}
return GenericList;
}
where del is a delegate. When calling this method, del should be the constructor of the specified class. Then, in all Model classes, I built a constructor that receives an object[] RowFromTable
public class MyClass
{
public int ID { get; set; }
public string Description { get; set; }
public FormaProcesso(object[] RowFromTable)
{
this.ID = (int)RowFromTable[0];
this.Description = RowFromTable[1].ToString();
}
}
Finally, to put it all together, this is what happens when I call the Web Method:
public List<MyClass> GetAll()
{
DataTable SPResult = MyWebService.GetAll().Table;
return Translate<MyClass>(SPResult, l => new MyClass(l));
}
Got the idea from here

windows phone 7 IsolatedStorageSettings.ApplicationSettings complex data

Just a quick question. In WP7, is it really bad design/idea to store complex data using IsolatedStorageSettings.ApplicationSettings? I want to save a collection of some class objects. The properties are marked with [DataMember] attributes.
An example of a class would be,
[DataContract]
public class OfflineItem
{
[DataMember]
public string Id { get; set; }
[DataMember]
public MyItem Item { get; set; }
[DataMember]
public Dictionary<string, string> KeyValues { get; set; }
}
Collection<OfflineItems> offlineItems = new Collection<OfflineItems>();
.....
IsolatedStorageSettings.ApplicationSettings["AllOfflineItems"] = offlineItems;
I tried it and it worked, but I want to know if it is a correct approach and will there be any performance hit in the long run?
#Jonna. I deliberated over this one too. I ended up using/adapating the following generic methods to serialize and deserialize using a IsolatedStorageFile as below. It includes deleting a file if it already exists as you are trying to update the data.
internal static void Write<T>(T obj, string fileName)
{
XmlWriterSettings writerSettings = new XmlWriterSettings
{
Indent = true,
IndentChars = "\t"
};
try
{
using (var isoStore = IsolatedStorageFile.GetUserStoreForApplication())
{
if (isoStore.FileExists(fileName))
{
isoStore.DeleteFile(fileName);
}
using (var isoStream = new IsolatedStorageFileStream(fileName, FileMode.Create, isoStore))
{
XmlSerializer serializer = new XmlSerializer(typeof(T));
using (XmlWriter xmlWriter = XmlWriter.Create(isoStream, writerSettings))
{
serializer.Serialize(xmlWriter, obj);
}
}
}
}
catch (IsolatedStorageException ex)
{
Debug.WriteLine(ex.Message);
}
catch (Exception emAll)
{
Debug.WriteLine(emAll.Message);
}
}
internal static T Read<T>(string fileName)
{
try
{
using (var isoStore = IsolatedStorageFile.GetUserStoreForApplication())
{
using (var isoStream = new IsolatedStorageFileStream(fileName, FileMode.Open, isoStore))
{
XmlSerializer serializer = new XmlSerializer(typeof(T));
return (T)serializer.Deserialize(isoStream);
}
}
}
catch (IsolatedStorageException ex)
{
Debug.WriteLine(ex.Message);
throw;
}
catch (Exception emAll)
{
Debug.WriteLine(emAll.Message);
throw;
}
}
Serialization would be called thus:
Serialization.Write<user>(userDetails, App.USERDETAILS);
And deserialization would be called thus:
Items = Serialization.Read<measurements>(App.MEASUREMENTS);
user is a class and userDetails is an object based on the that class. Measurements is a class and Items is an object based on that class. App.USERDETAILS & App.MEASUREMENTS are global strings that contain file names.
Some debug lines have been left in just so progress can be tracked.
It might also be worth considering using SQL + LINQ if you are thinking of migrating to Mango and much of this could be taken care of there...
I would serialize my data (either XML or Binary) to a separate file in IsolatedStorage. Because if IsolatedStorageSettings.ApplicationSettings is overcrowded it will take longer to load any of individual settings.
Here is a general purpose method to serialize your object to xml
public static string SerializeXml(object objectToSerialize)
{
using (var ms = new MemoryStream())
{
var serializer = new XmlSerializer(objectToSerialize.GetType());
serializer.Serialize(ms, objectToSerialize);
ms.Position = 0;
using (var reader = new StreamReader(ms))
{
return reader.ReadToEnd();
}
}
}

Resources