How do I query a SingleResult object in a ASP.NET based server? Please help with the below code.
public class UserController : TableController<User>
{
...
public Task DeleteUser(string id)
{
SingleResult<User> user = Lookup(id);
// I can drill down into user via the debugger and see the data
// I'm looking for. But I don't know how to translate what I see
// in the debugger to a .Net call.
// This is what I see in the debugger:
// new System.Linq.SystemCore_EnumerableDebugView
// <AlertMeService.DataObjects.User>(result.Queryable).Items[0].GroupNm
// which equals "fooGrp"
// The below call doesn't work
// string GroupNm = user.GroupNm;
// I need GroupNm from the object to send a group notification
PostNotification(user.GroupNm, ...);
return DeleteAsync(id);
}
...
Any help is greatly appreciated.
SingleResult returns an IQueryable, so use the Linq Single or SingleOrDefault methods to execute the query and get the result.
Single will throw an exception if 0, 2 or more values are returned, and SingleOrDefault will allow either 0 or 1 value and will throw if 2 or more than values are returned. If you want multiple values then use First/FirstOrDefault or Last/LastOrDefault, or some other terminal Linq method, as appropriate
SingleResult<User> userQuery = Lookup(id);
User user = userQuery.SingleOrDefault();
if( user == null ) {
}
else {
}
According to your description, I have checked the SingleResult class:
public sealed class SingleResult<T> : SingleResult
{
//
// Summary:
// Initializes a new instance of the System.Web.Http.SingleResult`1 class.
//
// Parameters:
// queryable:
// The System.Linq.IQueryable`1 containing zero or one entities.
public SingleResult(IQueryable<T> queryable);
//
// Summary:
// The System.Linq.IQueryable`1 containing zero or one entities.
public IQueryable<T> Queryable { get; }
}
Per my understanding, you could modify your DeleteUser method as follows:
public Task DeleteUser(string id)
{
SingleResult<User> result = Lookup(id);
var user=result.Queryable.SingleOrDefault();
if(user!=null)
{
//I need GroupNm from the object to send a group notification
PostNotification(user.GroupNm, ...);
return DeleteAsync(id);
}
return Task.FromException($"the specific user with userid:{id} is not found.");
}
Related
I have created service which communicates with my database. GetAvailableUserId service's method cannot be run simultaneously, because I don't want to return same user's id for two different calls. So far I have managed this:
public class UserService : IUserService
{
public int GetAvailableUserId()
{
using (var context = new UsersEntities())
{
using (var transaction = context.Database.BeginTransaction())
{
var availableUser = context.User
.Where(x => x.Available)
.FirstOrDefault();
if (availableUser == null)
{
throw new Exception("No available users.");
}
availableUser.Available = false;
context.SaveChanges();
transaction.Commit();
return availableUser.Id;
}
}
}
}
I wanted to test if service will work as intended, so I created simple console application to simulate synchronous requests:
Parallel.For(1, 100, (i, state) => {
var service = new UserServiceReference.UserServiceClient();
var id = service.GetAvailableUserId();
});
Unfortunately, It failed that simple test. I can see, that it returned same id for different for iterations.
Whats wrong there?
If I understood you correctly, you wan to lock method from other threads. If yesm then use lock:
static object lockObject = new object();
public class UserService : IUserService
{
public int GetAvailableUserId()
{
lock(lockObject )
{
// your code is omitted for the brevity
}
}
}
You need to spend some time and delve into the intricadies of SQL Server and EntityFramework.
Basically:
You need a database connection that handles repeatable results (which is a database connection string setting).
You need to wrap the interactions in EntityFramework within one transaction so that multiple instances do not possibly return the same result in the query and then make problems in the save.
Alternative method to achieve this is to catch DbUpdateConcurrencyException to check whether values in the row have changed since retrieving when you try to save.
So if e.g. the same record is retrieved twice. The first one to have the Available value updated in the database will cause the other one to thow concurrency exception when it tries to save because the value has changed since it was retrieved.
Microsoft - handling Concurrency Conflicts.
Add ConcurrencyCheck attribute above the Available property in your entity.
[ConcurrencyCheck]
public bool Available{ get; set; }
Then:
public int GetAvailableUserId()
{
using (var context = new UsersEntities())
{
try
{
var availableUser = context.User
.Where(x => x.Available)
.FirstOrDefault();
if (availableUser == null)
{
throw new Exception("No available users.");
}
availableUser.Available = false;
context.SaveChanges();
return availableUser.Id;
}
catch (DbUpdateConcurrencyException)
{
//If same row was already retrieved and updated to false, do not save, instead call the method again to get the next true row.
return GetAvailableUserId();
}
}
}
I have a service method:
public long InsertMessage(OutgoingInEntity input)
{
var request = new InsertOutgoingMessageRequest
{
Id = input.Id
... // fields
};
return Util.UsingWcfSync<IOutgoing, long>(client => client.InsertOutgoing(request));
}
I want to reuse this method in other context because I want 1 method which call this specific service, but the parameter OutgoingInEntity can change. When I call this method with other entities, the fields used in InsertOutgoingMessageRequest will be available and I will map like I did with the var request I cannot initiate InsertOutgoingMessageRequest in other context.
How can I say this input parameter is like generic and can be used for all kind of entities?
If you want to manage the object you receive you can just do this:
public long InsertMessage(Object input)
{
OutgoingInEntity yourObj = (OutgoingInEntity)input;
///.. your code ..///
}
Then you can do just the same for whatever you need.
I know this question has already been asked but I couldn't find an answer that satisfied me. What I am trying to do is to retrieve a particular DbSet<T> based on its type's name.
I have the following :
[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("MyDllAssemblyName")]
[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("MyCallingAssemblyName")]
class MyDbContext : DbContext {
public DbSet<ModelA> A { get; set; }
public DbSet<ModelB> B { get; set; }
public dynamic GetByName_SwitchTest(string name) {
switch (name) {
case "A": return A;
case "B": return B;
}
}
public dynamic GetByName_ReflectionTest(string fullname)
{
Type targetType = Type.GetType(fullname);
var model = GetType()
.GetRuntimeProperties()
.Where(o =>
o.PropertyType.IsGenericType &&
o.PropertyType.GetGenericTypeDefinition() == typeof(DbSet<>) &&
o.PropertyType.GenericTypeArguments.Contains(targetType))
.FirstOrDefault();
if (null != model)
return model.GetValue(this);
return null;
}
}
I have no trouble getting the type itself whether it is via a simple switch or reflection. I need however to return the type as a dynamic since I do not know what DbSet type it will be.
Then somewhere else in the same assembly, I use it this way :
// MyDbContext MyDbContextInstance..
var model = MyDbContextInstance.GetByName_SwitchTest("A");
var record1 = model.FirstOrDefault(); // It crashes here with RunTimeBinderException
At this point model contains an instance of a InternalDbSet<ModelA> type. From there, any use I do with the model object I get a RunTimeBinderException :
'Microsoft.Data.Entity.Internal.InternalDbSet' does not contain a definition for 'FirstOrDefault'
Investigating on the web, I found a blog post explaining that (dixit his blog) :
the reason the call to FirstOrDefault() fails is that the type
information of model is not available at runtime. The reason it's not
available is because anonymous types are not public. When the method
is returning an instance of that anonymous type, it's returning a
System.Object which references an instance of an anonymous type - a
type whose info isn't available to the main program.
And then he points that a solution :
The solution is actually quite simple. All we have to do is open up
AssemplyInfo.cs of the ClassLibrary1 project and add the following
line to it: [assembly:InternalsVisibleTo("assembly-name")]
I did try this solution on my code but it doesn't work. For info I have an asp.net 5 solution with two assemblies running on dnx dotnet46. An app and a dll containing all my models and DbContext. All the concerned calls I do are located on the dll though.
Does this solution have any chance to work ?
Am I missing something ?
Any pointers would be greatly appreciated ?
Thanks in advance
[EDIT]
I have tried to return IQueryable<dynamic> rather than dynamic and I could do the basic query model.FirstOrDefault(); but above all I'd like to be able to filter on a field too :
var record = model.FirstOrDefault(item => item.MyProperty == true);
So how did I do it when I am not aware of <T> during compile time.
First need to get the type as DbContext.Set method returns a non-generic DbSet instance for access to entities of the given type in the context and the underlying store.
public virtual DbSet Set(Type entityType)
Note here argument is the type of entity for which a set should be returned.And set for the given entity type is the return value.
var type = Assembly.GetExecutingAssembly().GetTypes().FirstOrDefault(t => t.Name == <Pass your table name>);
now once I have this type
if(type != null)
{
DbSet context = context.Set(type);
}
Or a one liner would be
DbSet mySet = context.Set(Type.GetType("<Your Entity Name>"));
*Disclaimer: This response doesn't give a stricto sensu answer to my question. It is rather a different approach to resolve my own problem. I am aware this is a specific example for a given situation that will not work for everyone. I am posting this approach in the hope it helps someone but will not mark it as the answer as I am still hoping for a real solution.
To start with, let's accept the fact that the only useful information we can get out of the current code is whether a record exists or not.. Any attempt of a dynamic queries after that would give the RuntimeBinderException.
Then let's continue with another fact; DbContext.Add(object) and DbContext.Update(object) are not template based so we can use them to save our models ( Instead of db.A.Add() or db.A.Update() )
In my own situation, no more is required to work out a procedure
Define models a little differently
To start with, I need a field that is retrievable across all my models which should obviously be a way to identify a unique record.
// IModel give me a reliable common field to all my models ( Fits my DB design maybe not yours though )
interface IModel { Guid Id { get; set; } }
// ModelA inherit IModel so that I always have access to an 'Id'
class ModelA : IModel {
public Guid Id { get; set; }
public int OtherField { get; set; }
}
// ModelB inherit IModel so that I always have access to an 'Id'
class ModelB : IModel {
public Guid Id { get; set; }
public string WhateverOtherField { get; set; }
}
Re-purpose the dynamic queries a bit to do something we know works
I haven't found a way to do smart query dynamically, so instead I know I can reliably identify a record and know if it exists or not.
class MyDbContext : DbContext {
public DbSet<ModelA> A { get; set; }
public DbSet<ModelB> B { get; set; }
// In my case, this method help me to know the next action I need to do
// The switch/case option is not pretty but might have better performance
// than Reflection. Anyhow, this is one's choice.
public bool HasRecord_SwitchTest(string name) {
switch (name) {
case "A": return A.AsNoTracking().Any(o => o.Id == id);
case "B": return B.AsNoTracking().Any(o => o.Id == id);
}
return false;
}
// In my case, this method help me to know the next action I need to do
public bool HasRecord_ReflectionTest(string fullname)
{
Type targetType = Type.GetType(fullname);
var model = GetType()
.GetRuntimeProperties()
.Where(o =>
o.PropertyType.IsGenericType &&
o.PropertyType.GetGenericTypeDefinition() == typeof(DbSet<>) &&
o.PropertyType.GenericTypeArguments.Contains(targetType))
.FirstOrDefault();
if (null != model)
return (bool)model.GetValue(this).AsNoTracking().Any(o => o.Id == id);
return false;
}
// Update and save immediately - simplified for example
public async Task<bool> UpdateDynamic(object content)
{
EntityEntry entry = Update(content, GraphBehavior.SingleObject);
return 1 == await SaveChangesAsync(true);
}
// Insert and save immediately - simplified for example
public async Task<bool> InsertDynamic(object content)
{
EntityEntry entry = Add(content, GraphBehavior.SingleObject);
return 1 == await SaveChangesAsync(true);
}
}
A little bit of plumbing to give a sense to my situation
Next, what I needed to do with that dynamic queries was a way to replicate data from a server down to my client. ( I have omitted a big chunk of the architecture to simplify this example )
class ReplicationItem
{
public ReplicationAction Action { get; set; } // = Create, Update, Delete
public string ModelName { get; set; } // Model name
public Guid Id { get; set; } // Unique identified across whole platform
}
Connecting the bits.
Now, here's the routine that connects the bits
public async void ProcessReplicationItem(ReplicationItem replicationItem)
{
using (var db = new MyDbContext())
{
// Custom method that attempts to get remote value by Model Name and Id
// This is where I get the strongly typed object
var remoteRecord = await TryGetAsync(replicationItem.ModelName, replicationItem.Id);
bool hasRemoteRecord = remoteRecord.Content != null;
// Get to know if a local copy of this record exists.
bool hasLocalRecord = db.HasRecord_ReflectionTest(replicationItem.ModelName, replicationItem.Id);
// Ensure response is valid whether it is a successful get or error is meaningful ( ie. NotFound )
if (remoteRecord.Success || remoteRecord.ResponseCode == System.Net.HttpStatusCode.NotFound)
{
switch (replicationItem.Action)
{
case ReplicationAction.Create:
{
if (hasRemoteRecord)
{
if (hasLocalRecord)
await db.UpdateDynamic(remoteRecord.Content);
else
await db.InsertDynamic(remoteRecord.Content);
}
// else - Do nothing
break;
}
case ReplicationAction.Update:
[etc...]
}
}
}
}
// Get record from server and with 'response.Content.ReadAsAsync' type it
// already to the appropriately
public static async Task<Response> TryGetAsync(ReplicationItem item)
{
if (string.IsNullOrWhiteSpace(item.ModelName))
{
throw new ArgumentException("Missing a model name", nameof(item));
}
if (item.Id == Guid.Empty)
{
throw new ArgumentException("Missing a primary key", nameof(item));
}
// This black box, just extrapolate a uri based on model name and id
// typically "api/ModelA/{the-guid}"
string uri = GetPathFromMessage(item);
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("http://localhost:12345");
HttpResponseMessage response = await client.GetAsync(uri);
if (response.IsSuccessStatusCode)
{
return new Response()
{
Content = await response.Content.ReadAsAsync(Type.GetType(item.ModelName)),
Success = true,
ResponseCode = response.StatusCode
};
}
else
{
return new Response()
{
Success = false,
ResponseCode = response.StatusCode
};
}
}
}
public class Response
{
public object Content { get; set; }
public bool Success { get; set; }
public HttpStatusCode ResponseCode { get; set; }
}
ps: I am still interested in a real answer, so please keep posting for other answer if you have a real one to share.
You could use this to get the DBSet for a specific type:
public object GetByType(DbContextcontext, Type type) {
var methode = _context.GetType().GetMethod("Set", types: Type.EmptyTypes);
if (methode == null) {
return null;
}
return methode.MakeGenericMethod(type).Invoke(_context, null);
}
I am having issues in trying to query my Azure DocumentDb storage account when attempting to retrieve a single record. This is my WebAPI code:
// Controller...
public AccountController : ApiController {
// other actions...
[HttpGet]
[Route("Profile")]
public HttpResponseMessage Profile()
{
var userId = User.Identity.GetUserId();
var rep = new DocumentRepository<UserDetail>();
var profile = rep.FindById(userId);
if (profile == null)
return Request.CreateErrorResponse(HttpStatusCode.NotFound, "Profile not found");
return Request.CreateResponse(HttpStatusCode.OK, profile);
}
}
// Repository
public class DocumentRepository<TEntity> : IDocumentRepository<TEntity> where TEntity : IIdentifiableEntity
{
private static DocumentClient _client;
private static string _databaseName;
private static string _documentsLink;
private static string _selfLink;
public DocumentRepository()
{
_client = new DocumentClient(new Uri(ConfigurationManager.AppSettings["DocumentDbEndpointUrl"]), ConfigurationManager.AppSettings["DocumentDbAuthKey"]);
_databaseName = ConfigurationManager.AppSettings["DocumentDbDatabaseName"];
var _database = ReadOrCreateDatabase();
var collection = InitialiseCollection(_database.SelfLink, EntityName);
_documentsLink = collection.DocumentsLink;
_selfLink = collection.SelfLink;
}
// other methods...
public TEntity FindById(string id)
{
return _client.CreateDocumentQuery<TEntity>(_documentsLink).SingleOrDefault(u => u.Id.ToString() == id);
}
}
It is this FindById method which causes the following issue:
An exception of type 'Microsoft.Azure.Documents.Linq.DocumentQueryException' occurred in Microsoft.Azure.Documents.Client.dll but was not handled in user code
Additional information: Query expression is invalid, expression return type
Foo.Models.DocumentDbEntities.UserDetail is unsupported. Query must evaluate to IEnumerable.
I don't understand what this error means, or how I fix it. I don't wish to return an IEnumerable or any descendant class as this method will return either 0 or 1 records. It works if I remove the SingleOrDefault clause, and change the return type to an IQueryable, however this is not what I want.
SingleOrDefault() is not supported, yet in the LINQ provider.
Change this to .Where(u => u.Id.ToString() == id).AsEnumberable().FirstOrDefault();
I can't say why Ryan's syntax stopped working for you, but you should be able to work around it without the extra performance hit by using a CreateDocumentQuery<>() overload with an explicitly-defined query string instead of using .Where():
string query = string.Format("SELECT * FROM docs WHERE docs.id = \"{0}\"", id);
return _client.CreateDocumentQuery<TEntity>(DocumentsLink, query).AsEnumerable().FirstOrDefault();
You might need to play with the query a little, but something of that form ought to work.
In our application, we are receiving a collection (List) as an input parameter to a WCF webmethod, and that input parameter is passed as is, without transferring to any local member, to a StaticClass.StaticMethod. Inside the static method, the first line checks the count of the input parameter List to greater than Zero and the next line I am retrieving the first element (0th index), but it throws “Index out of range” Error while this application is tested using load runner.
At first glance it appears like a simple race condition, but the load runner access this WCF service via a website and there no way the website can pass empty collection.
Any thoughts?
// Code snippet
public static List<X> GetCashBalances(List<Y> IPReceivedAtWebMethod)
{
List<X> list = new List<X>();
if IPReceivedAtWebMethod== null) return list;
if IPReceivedAtWebMethod.Count <= 0) return list;
// The below line throws Index out of range error.
SomeValue s = AdminHelper.GetSomeValue(IPReceivedAtWebMethod[0].member1);
// …
}
The WCF Service method calling the above method is given below for reference,
public class CashService : ICashService
{
public ServiceResponse GenerateCashBalances(RequestToWCFService request)
{
ServiceResponse response = DataContractFactory.InstanceOfServiceResponse();
try
{
// This is the code calling the method I referred in the question which is throwing Index out of range Error
response._someList = StaticClass.GetCashBalancesReferredInQuestion(request._someList);
// I hope this would not do any harm to _someList
List<CashBalance> list = response._someList.ConvertAll(c => (CashBalance)c);
// Second call using the same collection however the list is not alterned inside this method too.
response.someActivity = AdminController.GetActivity(request._someList).ToString("O");
response.ResponseCode = WcfServiceCodes.OK_RESPONSE;
}
catch (Exception ex)
{
// log error
}
return response;
}
Detail about the Request object
[DataContract]
public class RequestToWCFService : BaseRequest
{
[DataMember]
public List<AccountGroup> _someList { get; set; }
}
I'd take a look at how the list is being used by the calling method. It'd be pretty easy to say:
var balances = GetCashBalances(_someList);
... where _someList is a static field somewhere that gets consumed by a variety of different methods. If anything removes an element from _someList, you're prone to have the problem you're reporting.
See if this helps:
var list = _someList.ToList(); // create a local copy.
var balances = GetCashBalances(list);