Skip to content

Commit 9140c32

Browse files
more documentation
1 parent 160da2b commit 9140c32

File tree

2 files changed

+306
-2
lines changed

2 files changed

+306
-2
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,305 @@
1+
# **Setting Up Magic IndexedDB in Blazor**
2+
3+
## **1. Install the NuGet Package**
4+
5+
The first step is to install the **latest version** of **Magic IndexedDB** from NuGet:
6+
🔗 **[Magic.IndexedDb on NuGet](https://www.nuget.org/packages/Magic.IndexedDb/)**
7+
8+
Before updating, it's **highly recommended** to review the latest **release notes** to check for any important changes or enhancements:
9+
🔗 **[Release Notes & Updates](https://github.com/magiccodingman/Magic.IndexedDb/releases)**
10+
11+
---
12+
13+
## **2. Register the Magic IndexedDB Service**
14+
15+
Once installed, you must register **Magic IndexedDB** in your Blazor application's dependency injection container. Add the following to your **Program.cs** file:
16+
17+
### **🚀 Default Safe Message Limits**
18+
19+
```csharp
20+
// Default safe message limit for WASM applications
21+
builder.Services.AddMagicBlazorDB(BlazorInteropMode.WASM, builder.HostEnvironment.IsDevelopment());
22+
23+
// Default safe message limit for Blazor Hybrid applications (SignalR mode)
24+
builder.Services.AddMagicBlazorDB(BlazorInteropMode.SignalR, builder.HostEnvironment.IsDevelopment());
25+
```
26+
27+
### **📏 Custom Message Limit (Advanced)**
28+
29+
If you need to **customize** the message size limit (in bytes), you can specify it manually:
30+
31+
```csharp
32+
// Custom message limit of 35MB
33+
long customMessageLimitBytes = 35 * 1024 * 1024;
34+
builder.Services.AddMagicBlazorDB(customMessageLimitBytes, builder.HostEnvironment.IsDevelopment());
35+
```
36+
37+
### **🔹 Understanding Interop Modes**
38+
39+
|**Interop Mode**|**Use Case**|
40+
|---|---|
41+
|`BlazorInteropMode.WASM`|Used for **standalone Blazor WebAssembly applications**|
42+
|`BlazorInteropMode.SignalR`|Recommended for **Blazor Hybrid applications** where SignalR is used for communication|
43+
44+
The interop mode determines **how** the JavaScript and C# layers communicate. The **message limit** controls **how much data** can be sent between IndexedDB and C#. **A higher limit increases speed but also memory usage**, so tune it based on your needs.
45+
46+
---
47+
48+
## **3. Debug vs. Production Mode**
49+
50+
The second parameter in `AddMagicBlazorDB` is:
51+
52+
```csharp
53+
builder.HostEnvironment.IsDevelopment()
54+
```
55+
56+
This boolean **indicates whether the application is in Debug mode or not**.
57+
58+
### **🛠 Why This Matters?**
59+
60+
- When **enabled in development**, Magic IndexedDB **validates your database schema** at startup.
61+
- It performs **system reflection-based validation** to **detect potential issues early**.
62+
- In **production mode**, validation is **skipped** to avoid unnecessary performance overhead.
63+
- **AOT Compatibility**: Reflection-based validation may not work in **Ahead-of-Time (AOT) compiled scenarios**. Keeping it enabled **only in development** ensures a smooth experience.
64+
65+
> **TL;DR:** In **development mode**, Magic IndexedDB **protects you from mistakes** by validating your setup **before you run into issues**. In **production mode**, it prioritizes **speed and efficiency**.
66+
67+
---
68+
69+
## **4. Defining Your IndexedDB Schema**
70+
71+
### **Understanding IndexedDB Repositories**
72+
73+
Unlike traditional databases, **IndexedDB operates differently**. **Think of repositories like defining tables** rather than databases.
74+
75+
To create a schema, **define a repository** in your Blazor project or any referenced project.
76+
77+
---
78+
79+
### **5. Creating the IndexedDB Context**
80+
81+
Inside your Blazor project (or a referenced project), create a new **C# file** (e.g., `IndexedDbContext.cs`) and **implement `IMagicRepository`**:
82+
83+
```csharp
84+
public class IndexedDbContext : IMagicRepository
85+
{
86+
public static readonly IndexedDbSet Client = new("Client");
87+
public static readonly IndexedDbSet Employee = new("Employee");
88+
public static readonly IndexedDbSet Animal = new("Animal");
89+
}
90+
```
91+
92+
### **🔍 How It Works**
93+
94+
- The system will **automatically detect** this repository **no matter where it is**, even if it resides in a **referenced project**. It's detected by the **`IMagicRepository`** interface itself being attached.
95+
- Why this is exists will be shown below.
96+
97+
> **💡 Important:**
98+
> This setup **alone** is enough to define basic IndexedDB tables.
99+
> **For complex migration support, additional steps will be needed later**.
100+
101+
# **Defining Tables in Magic IndexedDB**
102+
103+
## **1. Understanding Tables in Magic IndexedDB**
104+
105+
Tables in **Magic IndexedDB** are **universally reusable** across any IndexedDB database you deploy. Defining a table is as simple as **creating a C# class** that represents your data and appending it with the appropriate **Magic IndexedDB interfaces and tools**.
106+
107+
Each table:
108+
109+
- **Defines its schema** with properties.
110+
- **Registers its database associations**.
111+
- **Supports compound keys, indexes, and unique constraints**.
112+
- **Automatically migrates when you modify its structure**.
113+
114+
---
115+
116+
## **2. Creating a Table (Basic Example)**
117+
118+
To define a table, you must:
119+
120+
1. Create a **class** that represents your data.
121+
2. Inherit from `MagicTableTool<T>`.
122+
3. Implement `IMagicTable<TDbSets>`.
123+
4. Define indexes, keys, and other configurations as needed.
124+
125+
### **📌 Example: Defining a `Person` Table**
126+
127+
```csharp
128+
public class Person : MagicTableTool<Person>, IMagicTable<DbSets>
129+
{
130+
public static readonly IndexedDbSet Client = IndexDbContext.Client;
131+
132+
public IMagicCompoundKey GetKeys() =>
133+
CreatePrimaryKey(x => x.Id, true); // Auto-incrementing primary key
134+
135+
public string GetTableName() => "Person";
136+
public IndexedDbSet GetDefaultDatabase() => IndexDbContext.Client;
137+
138+
public DbSets Databases { get; } = new();
139+
public sealed class DbSets
140+
{
141+
public readonly IndexedDbSet Client = IndexDbContext.Client;
142+
public readonly IndexedDbSet Employee = IndexDbContext.Employee;
143+
}
144+
145+
[MagicIndex] // Creates an index on this field
146+
public string Name { get; set; }
147+
148+
[MagicUniqueIndex("guid")] // Unique constraint
149+
public Guid UniqueGuid { get; set; } = Guid.NewGuid();
150+
151+
public int Age { get; set; }
152+
153+
[MagicNotMapped] // Exclude from IndexedDB schema
154+
public string Secret { get; set; }
155+
}
156+
```
157+
158+
---
159+
160+
## **3. Breaking Down the Table Definition**
161+
162+
### **🛠 Understanding `DbSets`**
163+
164+
The `<TDbSets>` type parameter in `IMagicTable<TDbSets>` exists to enforce **clean C# code structure**.
165+
166+
- You **define `DbSets` however you like**, but it **must include**:
167+
168+
```csharp
169+
public TDbSets Databases { get; } = new();
170+
```
171+
172+
- This makes the query system **strongly typed**, allowing clean LINQ queries like:
173+
174+
```csharp
175+
await _MagicDb.Query<Person>(x => x.Databases.Client);
176+
```
177+
178+
If you're unfamiliar with this pattern, **review the [Introduction Page](https://github.com/magiccodingman/Magic.IndexedDb/blob/master/MagicIndexDbWiki/Getting-Started-Blazor/P1-Introduction.md)**.
179+
180+
---
181+
182+
## **4. Defining Keys & Indexes**
183+
184+
### **🔑 Setting the Primary Key**
185+
186+
```csharp
187+
public IMagicCompoundKey GetKeys() =>
188+
CreatePrimaryKey(x => x.Id, true);
189+
```
190+
191+
- The **first parameter** is the **primary key property**.
192+
- The **second parameter** (`true` or `false`) sets **auto-incrementing** behavior.
193+
194+
### **🗝 Defining a Compound Key**
195+
196+
```csharp
197+
public IMagicCompoundKey GetKeys() =>
198+
CreateCompoundKey(x => x.Field1, x => x.Field2);
199+
```
200+
201+
- **Compound keys combine multiple fields** as a unique key.
202+
- **Auto-incrementing** is **not allowed** on compound keys.
203+
204+
---
205+
206+
## **5. Additional Table Configurations**
207+
208+
### **📌 `GetTableName()` – Table Naming**
209+
210+
Sets the table name in IndexedDB:
211+
212+
```csharp
213+
public string GetTableName() => "Person";
214+
```
215+
216+
This lets you **rename** your C# class **without breaking migrations**.
217+
218+
### **📌 `GetDefaultDatabase()` – Default Storage Location**
219+
220+
```csharp
221+
public IndexedDbSet GetDefaultDatabase() => IndexDbContext.Client;
222+
```
223+
224+
Tells the system which **database** this table belongs to by default.
225+
226+
---
227+
228+
## **6. Using Attributes for IndexedDB Optimization**
229+
230+
### **🔍 `MagicName` – Rename Columns in IndexedDB**
231+
232+
```csharp
233+
[MagicName("_id")]
234+
public int Id { get; set; }
235+
```
236+
237+
- **Ensures column names stay consistent** in IndexedDB.
238+
- **Highly recommended** to prevent migration issues when renaming C# properties.
239+
240+
### **📌 `MagicIndex` – Create an Indexed Column**
241+
242+
```csharp
243+
[MagicIndex]
244+
public string Name { get; set; }
245+
```
246+
247+
Speeds up queries using this field.
248+
249+
### **📌 `MagicUniqueIndex` – Unique Constraints**
250+
251+
```csharp
252+
[MagicUniqueIndex("guid")]
253+
public Guid UniqueGuid { get; set; } = Guid.NewGuid();
254+
```
255+
256+
Prevents duplicate values in this column.
257+
258+
### **📌 `MagicNotMapped` – Exclude Fields from IndexedDB**
259+
260+
```csharp
261+
[MagicNotMapped]
262+
public string Secret { get; set; }
263+
```
264+
265+
Keeps the property **in C# but out of IndexedDB**.
266+
267+
---
268+
269+
## **7. Nested Objects in IndexedDB**
270+
271+
Yes, **Magic IndexedDB supports nested objects**!
272+
273+
```csharp
274+
public class Address
275+
{
276+
public string City { get; set; }
277+
public string State { get; set; }
278+
}
279+
280+
public class Person : MagicTableTool<Person>, IMagicTable<DbSets>
281+
{
282+
public Address HomeAddress { get; set; } = new Address();
283+
}
284+
```
285+
286+
- **Fully supported** by the custom-built serializer.
287+
- **Validations ensure** that your schema remains stable.
288+
289+
---
290+
291+
## **8. Schema Validation & Protection**
292+
293+
Magic IndexedDB **validates your schema** to **prevent broken tables**: ✔ **Ensures compound keys don’t have forbidden names like `id`**.
294+
**Warns you if you rename fields without using `[MagicName]`**.
295+
**Protects you from invalid IndexedDB constraints**.
296+
297+
---
298+
299+
## **9. Next Steps – Handling Migrations**
300+
301+
Once you’ve defined your tables, the **next critical step is handling migrations**.
302+
Schema changes need to be **tracked and managed** so you don’t lose data.
303+
304+
🔥 **Learn how to handle migrations:**
305+
**[Check out the Magic IndexedDB Migrations Guide](https://github.com/magiccodingman/Magic.IndexedDb/blob/master/MagicIndexDbWiki/Getting-Started-Blazor/P3-Migrations.md)**

TestWasm/Models/Person.cs

+1-2
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@ public sealed class DbSets
4040

4141
public Nested Nested { get; set; } = new Nested();
4242

43-
//[MagicPrimaryKey(true, "id")]
4443
[MagicName("_id")]
4544
public int _Id { get; set; }
4645

@@ -56,7 +55,7 @@ public sealed class DbSets
5655
[MagicName("Age")]
5756
public int _Age { get; set; }
5857

59-
[MagicIndex]
58+
[MagicIndex("TestInt")]
6059
public int TestInt { get; set; }
6160

6261
public DateTime? DateOfBirth { get; set; }

0 commit comments

Comments
 (0)