Is any way to pass the table name as a parameter and get the record from db with make generalized function
string table = "tbl_Category";
int Id = Class.getLastId(table);
Class.aspx
public static int getLastId(string table)
{
int lastID = 0;
using (HatnEntities context = new HatnEntities())
{
// Fetch Id of last record from table
var result = (from c in context.tbl_Category.OrderByDescending(u => u.Id) select new { Id = c.Id }).FirstOrDefault();
^
//any way to use table name from parameter value"+table+"
if (result != null)
{
lastID = Convert.ToInt32(result.Id);
}
obj.Id = lastID + 1;
context.tbl_Category.Add(obj);
context.SaveChanges();
}
return status;
}
Please let me know is it possible
You can use Set() which would require that passing your table string parameter, you must get the Type from your assembly.
context.Set<TypeFromTableStringParameter>() ...
This is what you would have to do if you just want to be able to access any table in EF:
public static int getLastId<T>()
where T : PrimaryKey
{
using (HatnEntities context = new HatnEntities())
{
// Fetch Id of last record from table
var result = (from c in context.Set<T>().OrderByDescending(u => u.Id) select new { Id = c.Id }).FirstOrDefault();
var lastID = 0;
if (result != null)
{
lastID = Convert.ToInt32(result.Id);
}
obj.Id = lastID + 1;
context.Set<T>().Add(obj);
context.SaveChanges();
}
// not sure where this comes from?
return status;
}
public abstract class PrimaryKey
{
public int Id { get; set; }
}
All of you Entities would need to inherit (extend) PrimaryKey in order for you to Select, Where or FirstOrDefault (etc. etc.) based on the property Id.
Related
I have two tables:
Employee: Id, Name, DepartmentId
Department: Id, Name
Employee.cs:
public int Id {get;set;}
public string Name {get;set;}
public int DepartmentId {get;set;}
Department.cs:
public int Id {get;set;}
public string Name {get;set;}
ViewModel: EmployeeDepartmentVM:
public Department department {get;set;}
public List<Employee> employees {get;set;}
To Join these two tables I have written this code:
SELECT E.* , D.Id as DId , D.Name as DName
from [Employee] as E
LEFT OUTER JOIN [Department] as D
ON E.DepartmentId = D.Id
where D.Id = 1
How do I get EmployeeDepartmentVM type from the above query?
I know if I write a model like my problem will be solved:
public int Id {get;set;}
public string Name {get;set;}
public int DepartmentId {get;set;}
public int DId {get;set;}
public string Name {get;set;}
But I don't want to write extra model. Simply want bind query data into EmployeeDepartmentVM type.
I really don't see what's the challenge. The EmployeeDepartmentVM definition implies that you need to group the result set by the Department. Assuming the result set is unordered, it can be achieved by simply maintaining a dictionary for locating the view models of the already added departments during the read.
Which leads to something like this:
static List<EmployeeDepartmentVM> GetEmployeeDepartmentVMList(DbCommand command)
{
var resultById = new Dictionary<int, EmployeeDepartmentVM>();
using (var reader = command.ExecuteReader())
{
var employeeIdCol = reader.GetOrdinal("Id");
var employeeNameCol = reader.GetOrdinal("Name");
var departmentIdCol = reader.GetOrdinal("DId");
var departmentNameCol = reader.GetOrdinal("DName");
while (reader.Read())
{
var departmentId = reader.GetInt32(departmentIdCol);
EmployeeDepartmentVM result;
if (!resultById.TryGetValue(departmentId, out result))
{
result = new EmployeeDepartmentVM
{
department = new Department(),
employees = new List<Employee>()
};
result.department.Id = departmentId;
result.department.Name = reader.GetString(departmentNameCol);
resultById.Add(departmentId, result);
}
var employee = new Employee();
employee.Id = reader.GetInt32(employeeIdCol);
employee.Name = reader.GetString(employeeNameCol);
employee.DepartmentId = departmentId;
result.employees.Add(employee);
}
}
return resultById.Values.ToList();
}
Some things to note. The way written, your SQL query implies that Department related fields can be null (LEFT OUTER JOIN). However, the WHERE clause and also the Employee model (DepartmentId field non nullable) implies that it cannot happen. If the intent is to include the departments with no employees, then better change the join to RIGHT OUTER and use something like this:
// ...
if (reader.IsDBNull(employeeIdCol)) continue;
var employee = new Employee();
// ...
EDIT: For completeness, here is another approach. It's similar to the way EF materializes similar queries and does not need temporary dictionary, but requires the input set to be ordered by the PK of the master table, so you need to add
ORDER BY D.Id
at the end of your SQL. Databases can easily and efficiently provide such ordering, and the benefit of this solution is that it allows deferred execution and does not require processing the whole set in order to start returning results. It's not essential if you want to just get a list, but can be useful in other scenarios.
static IEnumerable<EmployeeDepartmentVM> GetEmployeeDepartmentVMs(DbCommand command)
{
using (var reader = command.ExecuteReader())
{
var employeeIdCol = reader.GetOrdinal("Id");
var employeeNameCol = reader.GetOrdinal("Name");
var departmentIdCol = reader.GetOrdinal("DId");
var departmentNameCol = reader.GetOrdinal("DName");
for (bool more = reader.Read(); more;)
{
var result = new EmployeeDepartmentVM
{
department = new Department(),
employees = new List<Employee>()
};
result.department.Id = reader.GetInt32(departmentIdCol);
result.department.Name = reader.GetString(departmentNameCol);
do
{
if (reader.IsDBNull(employeeIdCol)) continue;
var employee = new Employee();
employee.Id = reader.GetInt32(employeeIdCol);
employee.Name = reader.GetString(employeeNameCol);
employee.DepartmentId = result.department.Id;
result.employees.Add(employee);
}
while ((more = reader.Read()) && reader.GetInt32(departmentIdCol) == result.department.Id);
Debug.Assert(!more || reader.GetInt32(departmentIdCol) > result.department.Id); // Sanity check
yield return result;
}
}
}
To get a list as in the first approach, just add ToList() after the call, e.g.
var result = GetEmployeeDepartmentVMs(command).ToList();
I am trying to retrieve all business units from CRM 2013.
Tried the following query
var query = _serviceContext.BusinessUnitSet
.Where(b => b.EntityState == 0)
.Select(x => new
{
Name = x.Name,
Id = x.Id
}
)
.ToList();
Using this query I am receiving an error just stating:
{System.ServiceModel.FaultCode} {attributeName} {System.Collections.Generic.SynchronizedReadOnlyCollection<System.ServiceModel.FaultReasonText>}
When googling on the subject I found information about how to retrieve single business units (which seems to be different from retrieving a "normal" entity), but not how to get them all (link).
Any help as to how I would retrieve all business units would be much appreciated.
Try this using QueryExpression
public class BusinessUnit
{
public Guid Id { get; set; }
public String Name { get; set; }
}
public void GetAllBusinessUnits(Action<QueryExpression> queryModifier = null)
{
foreach (BusinessUnit m in RetrieveAllBusinessUnit(this.Service, 1000, queryModifier))
{
//Console.WriteLine(m.Name);
}
}
public static IEnumerable<BusinessUnit> RetrieveAllBusinessUnit(IOrganizationService service, int count = 1000, Action<QueryExpression> queryModifier = null)
{
QueryExpression query = new QueryExpression("businessunit")
{
ColumnSet = new ColumnSet("businessunitid", "name"),
PageInfo = new PagingInfo()
{
Count = count,
PageNumber = 1,
PagingCookie = null,
}
};
if (queryModifier != null)
{
queryModifier(query);
}
while (true)
{
EntityCollection results = service.RetrieveMultiple(query);
foreach (Entity e in results.Entities)
{
yield return new BusinessUnit()
{
Id = e.GetAttributeValue<Guid>("businessunitid"),
Name = e.GetAttributeValue<String>("name")
};
}
if (results.MoreRecords)
{
query.PageInfo.PageNumber++;
query.PageInfo.PagingCookie = results.PagingCookie;
}
else
{
yield break;
}
}
}
I presume you want to get all active business units from system. So you must use IsDisabled property to get them. The property you use EntityState is used for tracking the entity state in context, not to indicate state of entity in CRM. See BusinessUnit Entity for more info about BU entity.
I have a EF4.1 class X and I want to make copy of that plus all its child records.
X.Y and X.Y.Z
Now if I do the following it returns error.
The property 'X.ID' is part of the object's key information and cannot be modified.
public void CopyX(long ID)
{
var c = db.Xs.Include("Y").Include("W").Include("Y.Z").SingleOrDefault(x => x.ID == ID);
if (c != null)
{
c.ID = 0;
c.Title = "Copy Of " + c.Title;
for (var m = 0; m < c.Ys.Count; m++)
{
c.Ys[m].ID = 0;
c.Ys[m].XID=0-m;
for (var p = 0; p < c.Ys[m].Zs.Count; p++)
{
c.Ys[m].Zs[p].XID = 0 - m;
c.Ys[m].Zs[p].ID = 0 - p;
}
}
for (var i = 0; i < c.Ws.Count; i++)
{
c.Ws[i].ID = 0 - i;
c.Ws[i].XID = 0;
}
db.Entry<Content>(c).State = System.Data.EntityState.Added;
db.SaveChanges();
}
}
Or Is there other way of making copy of entity objects.
NOTE: there are multiple properties in each W,X,Y,Z.
In entity-framework-5, this is insanely easy with the DbExtensions.AsNotracking().
Returns a new query where the entities returned will not be cached in the DbContext or ObjectContext.
This appears to be the case for all objects in the object graph.
You just have to really understand your graph and what you do and don't want inserted/duplicated into the DB.
Lets assume we have objects like:
public class Person
{
public int ID { get; set; }
public string Name { get; set; }
public virtual ICollection<Address> Addresses { get; set; }
}
public class Address
{
public int ID { get; set; }
public AddressLine { get; set; }
public int StateID { get; set; }
public ICollection<State> { get; set; }
}
So in order to Duplicate a person, I need to duplicate the addresses, but I don't want to duplicate the States.
var person = this._context.Persons
.Include(i => i.Addresses)
.AsNoTracking()
.First();
// if this is a Guid, just do Guid.NewGuid();
// setting IDs to zero(0) assume the database is using an Identity Column
person.ID = 0;
foreach (var address in person.Addresses)
{
address.ID = 0;
}
this._context.Persons.Add(person);
this._context.SaveChanges();
If you then wanted to then reuse those same objects again to insert a third duplicate, you'd either run the query again (with AsNoTracking()) or detach the objects (example):
dbContext.Entry(person).State = EntityState.Detached;
person.ID = 0;
foreach (var address in person.Addresses)
{
dbContext.Entry(address).State = EntityState.Detached;
address.ID = 0;
}
this._context.Persons.Add(person);
this._context.SaveChanges();
You need to make correct deep copy of the whole entity graph - the best way is to serialize the original entity graph to memory stream and deserialize it to a new instance. Your entity must be serializable. It is often used with DataContractSerializer but you can use binary serialization as well.
C is not a copy it is the record, the error you are getting is because you are trying to update it's primary key, even if you weren't it still wouldn't work. You need to make a new X entity and then copy the values from the properties of the retrieved entity and then insert the new entity.
Not sure if it works in 4.1, from http://www.codeproject.com/Tips/474296/Clone-an-Entity-in-Entity-Framework-4:
public static T CopyEntity<T>(MyContext ctx, T entity, bool copyKeys = false) where T : EntityObject
{
T clone = ctx.CreateObject<T>();
PropertyInfo[] pis = entity.GetType().GetProperties();
foreach (PropertyInfo pi in pis)
{
EdmScalarPropertyAttribute[] attrs = (EdmScalarPropertyAttribute[])pi.GetCustomAttributes(typeof(EdmScalarPropertyAttribute), false);
foreach (EdmScalarPropertyAttribute attr in attrs)
{
if (!copyKeys && attr.EntityKeyProperty)
continue;
pi.SetValue(clone, pi.GetValue(entity, null), null);
}
}
return clone;
}
You can copy related entites to your cloned object now too; say you had an entity: Customer, which had the Navigation Property: Orders. You could then copy the Customer and their Orders using the above method by:
Customer newCustomer = CopyEntity(myObjectContext, myCustomer, false);
foreach(Order order in myCustomer.Orders)
{
Order newOrder = CopyEntity(myObjectContext, order, true);
newCustomer.Orders.Add(newOrder);
}
I use Newtonsoft.Json, and this awesome function.
private static T CloneJson<T>(T source)
{
return ReferenceEquals(source, null) ? default(T) : JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(source));
}
I have two tables: Vehicles and Workers.
Vehicle(Id, Number)
Workers(Id, Name, ContractorVehicleNumber)
I would like to write lambda query to return all the vehicles and the contractor vehicles. Something like in sql:
SELECT Id, Number
FROM Vehicle
UNION
SELECT NULL, ContractorVehicleNumber
FROM Workers
This is what I made:
public IQueryable<Vehicle> Get(bool includeContractorVehicles)
{
IQueryable<Vehicle> query = GetQuery();
if (includeContractorVehicles == true)
{
WorkerRepository rep = new WorkerRepository();
IQueryable<Vehicle> contractorsVehicles = rep.GetWirkers().
Select(x => new Vehicle()
{
VehicleNumber = x.ContractorVehicleNumber
});
query = query.Union(contractorsVehicles);
}
return query;
}
But I get an exception:
The entity or complex type 'XXXXXXXX' cannot be constructed in a LINQ to Entities query.
You cannot construct mapped entity type in projection. Your former example will work only if you create a new special type used for projection:
public class VehicleResult
{
public string Number { get; set; }
... // If you don't need more then one column you can use simple type instead of custom class
}
And your method will look like:
public IQueryable<VehicleResult> Get(bool includeContractorVehicles)
{
IQueryable<VehicleResult> query = GetQuery().Select(v => new VehicleResult { ... });
if (includeContractorVehicles == true)
{
WorkerRepository rep = new WorkerRepository();
IQueryable<VehicleResult> contractorsVehicles = rep.GetWorkers().
Select(x => new VehicleResult()
{
Number = x.ContractorVehicleNumber
});
query = query.Union(contractorsVehicles);
}
return query;
}
You cant create entities in the select statement. Try this instead:
public class VehicleDTO
{
public int Id { get; set; }
public int Number { get; set; }
}
public IQueryable<VehicleDTO> Get(bool includeContractorVehicles)
{
var query = GetQuery().Select(x => new VehicleDTO(){ ID = c.ID, Number = c.Number });
if (includeContractorVehicles)
{
WorkerRepository rep = new WorkerRepository();
var contractorsVehicles = rep.GetWirkers().
Select(x => new VehicleDTO(){ Number = x.ContractorVehicleNumber});
query = query.Union(contractorsVehicles);
}
return query;
}
Also are you sure you want a Union and not a Concat ?
I want to match 2 identical tables:
sourceProducts (productName, ProductionDate, ManID, shipper, distributer)
CommProducts (productName, ProductionDate, ManID, shipper, distributer)
but the number of rows and the record contents may differ. How do I select a certain record = raw from one table and get its clone record from the other table (e.g., check if the same record exists)? How do I do this using LinQ?
UPDATE: Here's the LINQ code:
protected void checkBtn_Click(object sender, EventArgs e)
{
MyProductsDataContext mySdb = new MyProductsDataContext();
Product mypro = new Product { ManId = int.Parse(TxtManI.Text), ProductName = TxtProN.Text, ProductionDate =DateTime .Parse ( TxtProDat.Text), Shipper = TxtShipI.Text, Distributer = TxtDistI.Text };
var spro = (from p in mySdb.Products
select new { p.ManId, p.ProductName, p.ProductionDate, p.Shipper, p.Distributer }).
Intersect(from s in mySdb.SourceProducts select new { s.ManId, s.ProductName, s.ProductionDate, s.Shipper, s.Distributer });
if (spro != null)
{
LblMessage.Text = "Acceptable product Data Inserted Sucessfully";
InsertData();
}
else
{
LblMessage.Text = "Invalid Product or bad Entry Please retype";
}
}
I would join on ManId and then compare the rest of the values in a where clause:
bool productExists = (
from p in mySdb.Products
join s in mySdb.SourceProducts
on p.ManId equals s.ManId
where p.ProductName == s.ProductName
&& p.ProductionDate == s.ProductionDate
&& p.Shipper == s.Shipper
&& p.Distributer = s.Distributer
select new { p.ManId, p.ProductName, p.ProductionDate, p.Shipper, p.Distributer }
).Any();
if (productExists)
{
LblMessage.Text = "Acceptable product Data Inserted Sucessfully";
InsertData();
}
else
{
LblMessage.Text = "Invalid Product or bad Entry Please retype";
}
I've used Any() to produce an efficient EXISTS SQL query. You could use SingleOrDefault() or FirstOrDefault() instead if you actually need to use the product returned.
I also don't see anywhere that you're using your new Product's ID - you might need to add that filter to the query as well:
Product mypro = new Product { ... };
bool productExists = (
from p in mySdb.Products
where p.ManId equals mypro.ManId
join s in mySdb.SourceProducts
on p.ManId equals s.ManId
...
You can probably do this using a join but I've hobbled together a unit test which shows one way to this
public class TestProduct
{
public int ManId { get; set; }
public string ProductName { get; set; }
public DateTime ProductionDate { get; set; }
public string Shipper { get; set; }
public string Distributor { get; set; }
}
[TestMethod]
public void TestSourceTable()
{
// Set up a test list
var list = new List<TestProduct>();
for (int i=0;i<5;i++)
{
var p = new TestProduct
{
Distributor = "D" + i,
ManId = i,
ProductionDate = DateTime.Now,
ProductName = "P" + i,
Shipper = "S" + i
};
list.Add(p);
}
// Get an existing product
var existingProduct = list[4];
// Get an unknown product
var unknownProduct = new TestProduct()
{
ManId = -1,
Distributor = "",
ProductionDate = DateTime.Now.AddDays(-1),
ProductName = "",
Shipper = ""
};
// product found
Assert.True(list.Any(p => p == existingProduct));
// product not found
Assert.False(list.Any(p => p == unknownProduct));
}