I have been reading the Datastore documentation about keys.
In the documentation it says
"a key is stored as an object not as a value."
This is the result
Below is a sample from my kind. ID is the key I am trying to retrieve to update and delete an entity
Display the results
@page
@using TestApp.Models
@model AllSportsStoreModel
<h2>Index</h2>
<p>
<a asp-page="SportsStore">New Item</a>
</p>
<table class="table">
<thead>
<tr>
<th>
@Html.DisplayName("ID")
</th>
<th>
@Html.DisplayName("Name")
</th>
<th>
@Html.DisplayName("Price")
</th>
<th>Edit | Delete</th>
</tr>
</thead>
<tbody>
@for (var i = 0; i < Model.SportsStoreList.Count; i++) {
<tr>
<td>
@Html.DisplayFor(model => model.SportsStoreList[i].Id)
</td>
<td>
@Html.DisplayFor(model => model.SportsStoreList[i].PName)
</td>
<td>
@Html.DisplayFor(model => model.SportsStoreList[i].Price)
</td>
<td>
<a asp-page="EditStore" asp-route-Id="SportsStoreList[i].Id">Edit</a> |
<a asp-page-handler="Delete" asp-route-Id="SportsStoreList[i].Id">Delete</a>
</td>
</tr>
}
</tbody>
</table>
<br />
Code Behind:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Google.Cloud.Datastore.V1;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using TestApp.Models;
namespace TestApp.Pages
{
public class AllSportsStoreModel : PageModel
{
private readonly ISportsStore stores;
public AllSportsStoreModel(ISportsStore stores)
{
this.stores = stores;
}
[BindProperty]
public List<Item> SportsStoreList { get; set; }
public IActionResult OnGet()
{
SportsStoreList = stores.ReadAll();
return Page();
}
}
}
DataStoreSportsStore.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Google.Cloud.Datastore.V1;
namespace TestApp.Models
{
public static class DatastoreBookStoreExtensionMethods
{
public static Key ToKey(this long id) => new Key().WithElement("Sports_db", id);
/// <summary>
/// Make a id given a datastore key.
/// </summary>
/// <param name="key">A datastore key</param>
/// <returns>A item id.</returns>
public static long ToId(this Key key) => key.Path.First().Id;
/// <summary>
/// Create a datastore entity with the same values as item.
/// </summary>
/// <param name="item">The item to store in datastore.</param>
/// <returns>A datastore entity.</returns>
public static Entity ToEntity(this Item item) => new Entity()
{
Key = item.Id.ToKey(),
["PName"] = item.PName,
["Price"] = item.Price,
};
/// <summary>
/// Unpack an itemfrom a datastore entity.
/// </summary>
/// <param name="entity">An entity retrieved from datastore.</param>
/// <returns>An Item.</returns>
public static Item ToItem(this Entity entity) => new Item()
{
Id = entity.Key.Path.First().Id,
PName = (string)entity["PName"],
Price = (string)entity["Price"]
};
}
public class DatastoreSportsStore : ISportsStore
{
string kind = "Sports_db";
private readonly DatastoreDb _db;
public DatastoreSportsStore()
{
_db = DatastoreDb.Create("projectid");
}
public void Create(Item item)
{
var entity = item.ToEntity();
entity.Key = _db.CreateKeyFactory(kind).CreateIncompleteKey();
var keys = _db.Insert(new[] { entity });
item.Id = keys.First().Path.First().Id;
}
public Item Read(long id)
{
return _db.Lookup(id.ToKey())?.ToItem();
}
public List<Item> ReadAll()
{
var query = new Query(kind);
var results = _db.RunQuery(query);
return results.Entities.Select(entity => entity.ToItem()).ToList();
}
public void Update(Item item)
{
_db.Update(item.ToEntity());
}
public void Delete(long id)
{
_db.Delete(id.ToKey());
}
}
}
Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddScoped<ISportsStore, DatastoreSportsStore>();
services.AddMvc();
}
Item.cs
namespace TestApp.Models
{
public class Item
{
public long Id { get; set; }
public string PName { get; set; }
public string Price { get; set; }
}
}
How does one retrieve a key from the Datastore Entity to update and delete records using C#?
How does one retrieve a key from the Datastore Entity using C#?
By calling the Entity.Key
property as mention in the documentation
Key key = entity.Key;
Working with entities
Applications can use the Cloud Datastore API to create, retrieve, update, and delete entities. If the application knows the complete key for an entity (or can derive it from its parent key, kind, and identifier), it can use the key to operate directly on the entity.
Updating an entity
To update an existing entity, modify the properties of the entity previously retrieved and store it using the key:
_item["Name"] = "John";
_item["Price"] = 12.95;
_db.Update(_item);
Deleting an entity
Given an entity's key, you can delete the entity:
_db.Delete(_item.Key);
The assumption above is that _item
is a variable of type Entity
.
Reference Cloud Datastore Documentation: Entities, Properties, and Keys
Following a very helpful tutorial here
Using Cloud Datastore with .NET
you can try the following.
Assuming you have a model like this (Taken from one of your previous questions)
public class Item {
public string Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
}
Note the Id
There was a link to some helper methods on GitHub. That can be adapted to your scenario.
Like
/// <summary>
/// Make a datastore key given a item's id.
/// </summary>
/// <param name="id">An Item's id.</param>
/// <returns>A datastore key.</returns>
public static Key ToKey(this string id) =>
new Key().WithElement("Sports_db", id);
/// <summary>
/// Make a id given a datastore key.
/// </summary>
/// <param name="key">A datastore key</param>
/// <returns>A item id.</returns>
public static string ToId(this Key key) => key.Path.First().Name;
/// <summary>
/// Create a datastore entity with the same values as item.
/// </summary>
/// <param name="item">The item to store in datastore.</param>
/// <returns>A datastore entity.</returns>
public static Entity ToEntity(this Item item) => new Entity() {
Key = item.Id.ToKey(),
["Name"] = item.Name,
["Price"] = item.Price,
};
/// <summary>
/// Unpack an itemfrom a datastore entity.
/// </summary>
/// <param name="entity">An entity retrieved from datastore.</param>
/// <returns>An Item.</returns>
public static Item ToItem(this Entity entity) => new Item() {
Id = entity.Key.ToId(),
Name = (string)entity["Name"],
Price = (decimal)entity["Price"]
};
This would allow you to use the extension method to do the following
SportsStoreList = stores.Select(entity => entity.ToItem()).ToList();
Again this was taken from a previous question.
So now that you have an Id/Key to work with you should now be able to carry out updates based on the Id/Key
When editing an item you can
var entity = item.ToEntity()
_db.Update(entity);
For the delete you can just convert the Id back to a Key
var key = item.Id.ToKey();
_db.Delete(key);
Taking it a step further, you can encapsulate the Datastore behind an abstraction that provides CRUD functionality and keeps all the Datastore related features in one central area
public class DatastoreSportsStore : ISportsStore {
string kind = "Sports_db";
private readonly DatastoreDb _db;
public DatastoreSportsStore() {
_db = DatastoreDb.Create("projectid");
}
public void Create(Item item) {
var entity = item.ToEntity();
entity.Key = _db.CreateKeyFactory(kind).CreateIncompleteKey();
var keys = _db.Insert(new[] { entity });
item.Id = keys.First().ToId();
}
public Item Read(string id) {
return _db.Lookup(id.ToKey())?.ToItem();
}
public List<Item> ReadAll() {
var query = new Query(kind);
var results = _db.RunQuery(query);
return results.Entities.Select(entity => entity.ToItem()).ToList();
}
public void Update(Item item) {
_db.Update(item.ToEntity());
}
public void Delete(string id) {
_db.Delete(id.ToKey());
}
}
That way there is no need to interact with the Datastore in your page models.
You would register the abstraction with the service collection during start up
Reference Introduction to Razor Pages in ASP.NET Core
Startup.cs:
public class Startup {
public void ConfigureServices(IServiceCollection services) {
//...
services.AddScoped<ISportsStore, DatastoreSportsStore>();
//...
// Includes support for Razor Pages and controllers.
services.AddMvc();
}
//...
}
And then inject that as the dependency where needed.
For example,
AllSportsStore.cshtml.cs
public class AllSportsStoreModel : PageModel {
private readonly ISportsStore stores;
public AllSportsStoreModel(ISportsStore stores) {
this.stores = stores;
}
[BindProperty]
public List<Item> SportsStoreList { get; set; }
public IActionResult OnGet() {
SportsStoreList = stores.ReadAll();
return Page();
}
}
In the above PageMode
the abstracted store is injected and used to get the items to be displayed in the view
You should then be able to access the items in the list in the view/page.
AllSportsStore.cshtml
@page
@using TestApp.Models
@model AllSportsStoreModel
<h2>Index</h2>
<p>
<a asp-page="SportsStore">New Item</a>
</p>
<table class="table">
<thead>
<tr>
<th>
@Html.DisplayName("ID")
</th>
<th>
@Html.DisplayName("Name")
</th>
<th>
@Html.DisplayName("Price")
</th>
<th>Edit | Delete</th>
</tr>
</thead>
<tbody>
@for (var i = 0; i < Model.SportsStoreList.Count; i++) {
<tr>
<td>
@Html.DisplayFor(model => model.SportsStoreList[i].Id)
</td>
<td>
@Html.DisplayFor(model => model.SportsStoreList[i].Name)
</td>
<td>
@Html.DisplayFor(model => model.SportsStoreList[i].Price)
</td>
<td>
<a asp-page="EditStore" asp-route-Id="@(Model.SportsStoreList[i].Id)">Edit</a> |
<a asp-page-handler="Delete" asp-route-Id="@(Model.SportsStoreList[i].Id)">Delete</a>
</td>
</tr>
}
</tbody>
</table>
<br />
If '_'
is your variable name of the entity, then to get the key for the entity you'll call the Entity.Key property on the entity.
i.e:
Id = _.Key,
There is no need for casting it like the other members in the provided example..
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With