Entity Random Select from DB C# MVC - c#

Try to find the solution but i cant.
So problem is next one. I have the EDM model of database. I have a class with functions to get data from DB.
Like this:
public IQueryable<photos> FindUserPhotos(string userlogin)
{
return from m in db.photos
where m.userlogin == userlogin
select m;
}
How to get the Random 10 lines from DB?

I always use this method for get custom entity OrderBy(x => Guid.NewGuid())
public photos Find10RandomUserPhotos(string userlogin)
{
return db.photos.Where(x => x.userlogin == userlogin).OrderBy(x => Guid.NewGuid()).Take(10).ToList();
}

Following Random row from Linq to Sql
public photos FindRandomUserPhoto(string userlogin)
{
var qry = FindUserPhotos(userlogin);
int count = qry.Count();
int index = new Random().Next(count);
return qry.Skip(index).FirstOrDefault();
}
public Array<photos> Find10RandomUserPhotos(string userlogin)
{
var result = New Array<photos>;
for (i = 0; i < 10; i++) {
result.add(FindRandomUserPhoto(userlogin));
}
return result
}

Related

loop through sql results and delete the single rows

Im trying to delete persons from a list through a for loop. My problem is now that im trying to find each id to delete the specific row of my database but i dont know how i can do it with a for loop.
My Code right now:
[HttpPost("delUebertrag/")]
public async Task<ActionResult<ProzessPersonenzuordnungen>> delRecUebertrag([FromBody] recUebertragModel user)
{
ProzessPersonenzuordnungen ppz = new();
for (var i = 0; i <= user.personList.Length; i++)
{
Guid personId = new Guid(user.personList[i]);
ppz.ProzessId = new Guid(user.prozessId);
var prozessPersonenzuordnungen = _context.ProzessPersonenzuordnungens.Where(p => p.ProzessId == ppz.ProzessId && p.PersonId == personId);
if (prozessPersonenzuordnungen == null)
{
return NotFound();
}
//Everythings works fine above, prozessPersonenzuordnungen haves for Example 2 results
for(var j = 0; j < prozessPersonenzuordnungen.Count(); j++) // i dont know if Counts is fine, looking for something like length of the results
{
var toDeletingRow = await _context.ProzessPersonenzuordnungens.FindAsync(prozessPersonenzuordnungen.Select(p => p.ProzessPersonenzuordnungId)); // Here i need to go through every singleId of my results, something like p.ProzessPersonenzuordnungId[j](does not work)
_context.ProzessPersonenzuordnungens.Remove(toDeletingRow);
await _context.SaveChangesAsync();
}
}
return Ok();
}
The FindAsync can be only used for single item. Instead do
var rowsToDelete = _context.ProzessPersonenzuordnungens.Where(x=> prozessPersonenzuordnungen.Select(p => p.ProzessPersonenzuordnungId).Contains(x.Id));
And instead of Remove, use
_context.ProzessPersonenzuordnungens.RemoveRange(rowsToDelete);
And one important thing, accessing database in a loop is a very bad practice.
Try to do it without the loop.
Edit:
Try this
ProzessPersonenzuordnungen ppz = new ProzessPersonenzuordnungen();
for (var i = 0; i <= user.personList.Length; i++)
{
Guid personId = new Guid(user.personList[i]);
ppz.ProzessId = new Guid(user.prozessId);
var prozessPersonenzuordnungen = _context.ProzessPersonenzuordnungens.Where(p => p.ProzessId == ppz.ProzessId && p.PersonId == personId)
.Select((x)=> x.ProzessPersonenzuordnungId);
if (prozessPersonenzuordnungen == null)
{
return NotFound();
}
var rowsToDelete = _context.ProzessPersonenzuordnungens.Where(x => prozessPersonenzuordnungen.Contains(x.Id));
_context.ProzessPersonenzuordnungens.RemoveRange(rowsToDelete);
await _context.SaveChangesAsync();
return Ok();
}

How to use Out to pass multiple values from list in C#

I have a situation where I'm passing an array of data (it can be any number, not fixed) from front-end, which is received as list in my API. I need each of the record's primary key value in order to pass them in my controller again to do further task. But using out, I am not able to return multiple data, it only returns the final value after finishing the loop.
Code-
public bool Add(List<Model> model) //have tried using out, but not working as I want
{
Model obj = new Model();
bool saved = false;
int id = 0;
foreach (Model m in model)
{
var data = _repo.Get(x => x.Id == m.Id);
var isExist = _repo.AsQueryable().Count();
if (isExist <= 0)
{
maxId = 1;
}
else
{
maxId = _repo.AsQueryable().Max(x => x.Id) + 1;
}
obj.Id = maxId; //the maxId for each loop iteration needs to be passed as out to fulfill my situation
obj.Name= m.Name;
obj.Dept= m.Dept;
_repo.Add(obj);
isSaved = true;
}
return isSaved;
}
Is there any way to return the maxId after each iteration or all maxId all together to my controller?
To return all at once create a List and either make that the return type of the method:
public List<TypeYouWantToReturn> Add(...)
{
List<TypeYouWantToReturn> list = new List<TypeYouWantToReturn>();
//make a loop and add the results here: list.Add(something);
return list;
}
or make it an out parameter as you mentioned:
public bool Add(out List<TypeYouWantToReturn> list)
{
//make a loop and add the results here: list.Add(something);
return true;
}
or use yield return to return values one by one.

Merging lists with a for loop

I'm working on an algorithm which can generate 2 types of recommendations, restaurants and dishes. All of this works fine, but I wanted to merge these 2 types of recommendations in a single list, which is where I encountered some issues. From my previous question I concluded that I needed a wrapper class, which I have set up like this:
public class RecommenderItem
{
public Guid Id { get; set; }
public object Entity { get; set; }
}
Now I want to alternate the 2 types of recommendations so the list would look like this:
[Restaurant][Dish][Restaurant][Dish][Restaurant][Dish] //Etc...
Note that these recommendations are completely separate. They are generated purely based on the user's preference, and they have no correlation in between them. My product owner wants to show these recommendations on the home page of our app like this.
These lists are different in length, so if I have added all items from a list, I wanted to just add the remaining objects from the other list. A possible scenario of this could look like this:
/*Other objects before this...*/[Dish][Restaurant][Dish][Dish][Dish] //Etc...
Here did the list of restaurant objects run out and I just wanted to add the remaining dish recommendations at the end of the list.
I have gotten this far, but I'm unsure how I would catch an IndexOutOfBounds exception and add the rest of the remaining objects at the end.
public List<RecommenderItem> GetMergedRecommendationLists(List<Restaurant> restaurantRecommendations,
List<Dish> dishRecommendations)
{
//Setting up the output list.
List<RecommenderItem> output = new List<RecommenderItem>();
int count = 0;
//Check which list is longer and use that count
if (restaurantRecommendations.Count > dishRecommendations.Count)
count = dishRecommendations.Count;
else
count = restaurantRecommendations.Count;
for (int i = 0; i < count; i++)
{
//I'm fully aware this isn't the most optimal way of doing this,
//but I'm only looking at functionality here, optimizing performance comes later.
var restRecommendation = restaurantRecommendations[i];
var dishRecommendation = dishRecommendations[i];
output.Add(new RecommenderItem()
{
Id = restRecommendation.Id,
Entity = restRecommendation
});
output.Add(new RecommenderItem()
{
Id = dishRecommendation.Id,
Entity = dishRecommendation
});
}
return output;
}
Does anyone have an idea how I could do this? Could I just catch an IndexOutOfBounds exception and use .AddRange() for the remaining objects? I'm not sure how I could check which list was out of bounds.
Let me know if I should elaborate more and thanks in advance!
Edit: -removed because it wasn't fair.-
This is a fairly succinct way of doing this.
While not Linq, it works in the spirit of the way Linq works by deferring doing any work until the resulting sequence is enumerated:
public static IEnumerable<RecommenderItem> Merge(IEnumerable<Restaurant> restaurants, IEnumerable<Dish> dishes)
{
using (var r = restaurants.GetEnumerator())
using (var d = dishes.GetEnumerator())
{
while (true)
{
bool rAvailable = r.MoveNext();
bool dAvailable = d.MoveNext();
if (rAvailable)
yield return new RecommenderItem { Id = r.Current.Id, Entity = r.Current };
if (dAvailable)
yield return new RecommenderItem { Id = d.Current.Id, Entity = d.Current };
if (!rAvailable && !dAvailable)
break;
}
}
}
If you happen to be using the MoreLinq NuGet package that includes the ZipLongest extension method, you can use the following simplified implementation instead:
public static IEnumerable<RecommenderItem> Merge(IEnumerable<Restaurant> restaurants, IEnumerable<Dish> dishes)
{
foreach (var item in restaurants.ZipLongest(dishes, (r, d) => new { r, d }))
{
if (item.r != null)
yield return new RecommenderItem { Id = item.r.Id, Entity = item.r };
if (item.d != null)
yield return new RecommenderItem { Id = item.d.Id, Entity = item.d };
}
}
Addendum
As #InBetween posted in his answer, you can put the interleaving logic into an extension method. Here's my version; it's substantially the same, except I've added a small optimisation to avoid calling .MoveNext() when its not necessary:
public static class EnumerableExt
{
public static IEnumerable<T> Interleave<T>(this IEnumerable<T> a, IEnumerable<T> b)
{
using (var ae = a.GetEnumerator())
using (var be = b.GetEnumerator())
{
bool aAvailable = true;
bool bAvailable = true;
while (aAvailable || bAvailable)
{
aAvailable = aAvailable && ae.MoveNext();
bAvailable = bAvailable && be.MoveNext();
if (aAvailable)
yield return ae.Current;
if (bAvailable)
yield return be.Current;
}
}
}
}
Once you have that, I realised that you don't need to write an implict operator. Instead, you can just convert the two sequences to the resultant type before calling Interleave() like so:
var restaurantsAsRecommenderItems =
restaurantRecommendations
.Select(r => new RecommenderItem {Id = r.Id, Entity = r});
var dishesAsRecommenderItems =
dishRecommendations
.Select(d => new RecommenderItem {Id = d.Id, Entity = d});
var result =
restaurantsAsRecommenderItems
.Interleave(dishesAsRecommenderItems)
.ToList();
My recommendation would be to just make simple implicit operator :
public static implicit operator RecommenderItem(Restaurant restaurant) {
return new RecommenderItem { Id = restaurant.Id, Entity = restaurant };
}
Then you have possibility to convert these types easily like :
Restaurant rest = //...
RecommenderItem rItem = rest; // here the implicit operator is called
After doing this you can just use one for loop :
int count = Math.Max(restaurantRecommendations.Count, dishRecommendations.Count);
for ( int i = 0; i < count; i++ ) {
if ( i < restRecommendations.Count )
output.Add(restRecommendations[i]);
if ( i < dishRecommendations.Count )
output.Add(dishRecommendations[i]);
}
This will make your work much more easier.
Well, there are probably more elegant LINQ solutions but you have already most, it's also a very efficient approach:
public List<RecommenderItem> GetMergedRecommendationLists(List<Restaurant> restaurantRecommendations, List<Dish> dishRecommendations)
{
//Setting up the output list.
List<RecommenderItem> output = new List<RecommenderItem>();
int count = Math.Min(restaurantRecommendations.Count, dishRecommendations.Count);
for (int i = 0; i < count; i++)
{
var restRecommendation = restaurantRecommendations[i];
var dishRecommendation = dishRecommendations[i];
output.Add(new RecommenderItem()
{
Id = restRecommendation.Id,
Entity = restRecommendation
});
output.Add(new RecommenderItem()
{
Id = dishRecommendation.Id,
Entity = dishRecommendation
});
}
int remainingRestaurant = restaurantRecommendations.Count - count;
int remainingDishes = dishRecommendations.Count - count;
if (remainingRestaurant > 0)
{
for (int i = count; i < restaurantRecommendations.Count; i++)
{
var restRecommendation = restaurantRecommendations[i];
output.Add(new RecommenderItem()
{
Id = restRecommendation.Id,
Entity = restRecommendation
});
}
}
else if (remainingDishes > 0)
{
for (int i = count; i < dishRecommendations.Count; i++)
{
var dishRecommendation = dishRecommendations[i];
output.Add(new RecommenderItem()
{
Id = dishRecommendation.Id,
Entity = dishRecommendation
});
}
}
return output;
}
A simple way of doing it would be:
public static IEnumerable<T> Merge<T>(this IEnumerable<T> first, IEnumerable<T> second)
{
using (var firstEnumerator = first.GetEnumerator())
using (var secondEnumerator = second.GetEnumerator())
{
while (firstEnumerator.MoveNext())
{
yield return firstEnumerator.Current;
if (secondEnumerator.MoveNext())
{
yield return secondEnumerator.Current;
}
}
while (secondEnumerator.MoveNext())
{
yield return secondEnumerator.Current;
}
}
}
After having created two arrays of restaurants and dishes of the same type RecommenderItem, you can use the Zip method like :
var restaurants = restaurantRecommendations.Select(x => new RecommenderItem {
Id = x.Id,
Entity = x
}).ToArray();
var dishes = dishRecommendations.Select(x => new RecommenderItem {
Id = x.Id,
Entity = x
}).ToArray();
var output = restaurants.Zip(dishes, (r, d) => new[] { r, d })
.SelectMany(r => r).Concat(dishes.Skip(restaurants.Length))
.Concat(restaurants.Skip(dishes.Length));
Restaraunt and Dish would have to share a base type:
restaurantRecommendations.Select(item => new RecommenderItem()
{
Id = item.Id,
Entity = item
});
dishRecommendations.Select(item => new RecommenderItem()
{
Id = item.Id,
Entity = item
});
Once that's the case you could use something like this slightly modified version of Zip (from System.Linq):
private static IEnumerable<T> ZipThrough<T>(IEnumerable<T> first, IEnumerable<T> second)
{
if (first == null) throw new ArgumentNullException(nameof(first));
if (second == null) throw new ArgumentNullException(nameof(second));
using (var e1 = first.GetEnumerator())
{
using (var e2 = second.GetEnumerator())
{
while (true)
if (e1.MoveNext())
{
yield return e1.Current;
if (e2.MoveNext()) yield return e2.Current;
}
else if (e2.MoveNext())
{
yield return e2.Current;
}
else
{
break;
}
}
}
}

Querying the id of an entity using linq

In the following method I am trying to fetch the Username by passing the id value where the ids passed as parameter can be multiple values as in csv's (eg: 1,2) and are returned to the calling function as IEnumerable.
Code Follows as below :
[NonAction]
public static IEnumerable<UserProfile> SearchCMSAdmins(string s)
{
//var searchResults = Entities.UserProfiles.Where(item =>item.UserName.Contains(s));
//return searchResults;
string[] ids = s.Split(',');
IEnumerable<UserProfile> results = null;
IList<UserProfile> user = new List<UserProfile>();
for (int i = 0; i < ids.Length; i++)
{
int id = Convert.ToInt32(ids[i].ToString());
var entity = Entities.UserProfiles.Where(item => item.UserId);
//user.Add(entity);
results = results.Concat(entity);
}
return results;
}
Any help is appreciated.
Try using Contains:
var results = Entities.UserProfiles.Where(item => ids.Contains(item.UserId));
http://msdn.microsoft.com/en-us/library/ms132407.aspx
You can get the id array to be of int type, You can either use int.TryParse or Convert.ToInt32 like:
int[] ids = s.Split(',').Select(r=> Convert.ToInt32(r)).ToArray();
Later you can modify your LINQ query as:
IList<UserProfile> user = Entities.UserProfiles
.Where(item=> ids.Contains(item)).ToList();
This would be like Select * from table where ID in (1,2,3) see Creating IN Queries With Linq to SQL for idea
[NonAction]
public static IEnumerable<UserProfile> SearchCMSAdmins(string s)
{
string[] ids = s.Split(',');
foreach (string idAsString in ids)
{
int id = Convert.ToInt32(idAsString);
var entity = Entities.UserProfiles.Where(item => item.UserId == id);
yield return entity;
}
}
should do it (there should be some validation code too in case the id is not an int or the entity is null)

nhibernate random data from database

IList<Companies> companies = NHibernateSession.CreateCriteria(typeof(Companies))
.AddOrder(new RandomOrder())
.SetMaxResults(3)
.List<Companies>();
public class RandomOrder : Order
{
public RandomOrder() : base("", true) { }
public override NHibernate.SqlCommand.SqlString ToSqlString(ICriteria criteria, ICriteriaQuery criteriaQuery)
{
return new NHibernate.SqlCommand.SqlString("newid()");
}
}
how can i make random data from DB. 3 of them. Code i paste not working very well.
Something like this might work... though it'll require 2 db calls:
public IEnumerable<Company> GetRandomCompanies(int maxSelections)
{
try
{
IList<int> companyIds = _session.CreateCriteria<Company>() // get all available company ids
.SetProjection(LambdaProjection.Property<Company>(c => c.Id)).List<int>();
return _session.CreateCriteria<Company>()
.Add(Restrictions.In(LambdaProjection.Property<Company>(c => c.Id), GetRandomCompanyIds(companyIds.ToList(), maxSelections))) // get 3 random Ids
.List<Company>();
}
catch (Exception xpt)
{
ErrorSignal.FromCurrentContext().Raise(xpt);
}
return new List<Company>();
}
private List<int> GetRandomCompanyIds(List<int> companyIds, int maxSelections)
{
List<int> randomIds = new List<int>();
for (int i = 0; i <= maxSelections; i++)
{
// this will get you the same result all day, new next day
// it might not be what you need, so you could just use a new seed.
Random rng = new Random(DateTime.Now.DayOfYear);
randomIds.Add(companyIds[rng.Next(companyIds.Count)]);
}
return randomIds;
}
edit: also, I haven't tested this at all so who knows what it'll do! It should be at least on the right track. Maybe there's a way that doesn't require 2 db calls
In Nhibernate you can simply select random rows like so using SQL
var query = "SELECT top 3 * from [Companies] ORDER BY NEWID()";
ISQLQuery qry = session.CreateSQLQuery(query).AddEntity(typeof(Companies));
Companies randomCompanies = qry.List<Companies>();

Categories